summaryrefslogtreecommitdiff
path: root/lib/socks.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/socks.c')
-rw-r--r--lib/socks.c169
1 files changed, 96 insertions, 73 deletions
diff --git a/lib/socks.c b/lib/socks.c
index 44783d015..a2d1e621f 100644
--- a/lib/socks.c
+++ b/lib/socks.c
@@ -9,7 +9,7 @@
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
- * are also available at https://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
@@ -184,12 +184,12 @@ int Curl_SOCKS_getsock(struct connectdata *conn, curl_socket_t *sock,
* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
* Nonsupport "Identification Protocol (RFC1413)"
*/
-CURLcode Curl_SOCKS4(const char *proxy_user,
- const char *hostname,
- int remote_port,
- int sockindex,
- struct connectdata *conn,
- bool *done)
+CURLproxycode Curl_SOCKS4(const char *proxy_user,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn,
+ bool *done)
{
const bool protocol4a =
(conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
@@ -237,11 +237,11 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
Curl_resolv(conn, hostname, remote_port, FALSE, &dns);
if(rc == CURLRESOLV_ERROR)
- return CURLE_COULDNT_RESOLVE_PROXY;
+ return CURLPX_RESOLVE_HOST;
else if(rc == CURLRESOLV_PENDING) {
sxstate(conn, CONNECT_RESOLVING);
infof(data, "SOCKS4 non-blocking resolve of %s\n", hostname);
- return CURLE_OK;
+ return CURLPX_OK;
}
sxstate(conn, CONNECT_RESOLVED);
goto CONNECT_RESOLVED;
@@ -265,8 +265,11 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
}
else {
result = Curl_resolv_check(data->conn, &dns);
- if(!dns)
- return result;
+ if(!dns) {
+ if(result)
+ return CURLPX_RESOLVE_HOST;
+ return CURLPX_OK;
+ }
}
/* FALLTHROUGH */
CONNECT_RESOLVED:
@@ -303,7 +306,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
if(!hp) {
failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
hostname);
- return CURLE_COULDNT_RESOLVE_HOST;
+ return CURLPX_RESOLVE_HOST;
}
}
/* FALLTHROUGH */
@@ -316,8 +319,8 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
if(proxy_user) {
size_t plen = strlen(proxy_user);
if(plen >= sizeof(sx->socksreq) - 8) {
- failf(data, "Too long SOCKS proxy name, can't use!\n");
- return CURLE_COULDNT_CONNECT;
+ failf(data, "Too long SOCKS proxy user name, can't use!\n");
+ return CURLPX_LONG_USER;
}
/* copy the proxy name WITH trailing zero */
memcpy(socksreq + 8, proxy_user, plen + 1);
@@ -343,7 +346,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
strcpy((char *)socksreq + packetsize, hostname);
else {
failf(data, "SOCKS4: too long host name");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_LONG_HOSTNAME;
}
packetsize += hostnamelen;
}
@@ -358,13 +361,13 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
sx->outstanding, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to send SOCKS4 connect request.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_SEND_CONNECT;
}
if(written != sx->outstanding) {
/* not done, remain in state */
sx->outstanding -= written;
sx->outp += written;
- return CURLE_OK;
+ return CURLPX_OK;
}
/* done sending! */
@@ -380,18 +383,18 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
if(result && (CURLE_AGAIN != result)) {
failf(data, "SOCKS4: Failed receiving connect request ack: %s",
curl_easy_strerror(result));
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_RECV_CONNECT;
}
else if(!result && !actualread) {
/* connection closed */
failf(data, "connection to proxy closed");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_CLOSED;
}
else if(actualread != sx->outstanding) {
/* remain in reading state */
sx->outstanding -= actualread;
sx->outp += actualread;
- return CURLE_OK;
+ return CURLPX_OK;
}
sxstate(conn, CONNECT_DONE);
break;
@@ -422,7 +425,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
if(socksreq[0] != 0) {
failf(data,
"SOCKS4 reply has wrong version, version should be 0.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_BAD_VERSION;
}
/* Result */
@@ -438,7 +441,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
(((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
(unsigned char)socksreq[1]);
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_REQUEST_FAILED;
case 92:
failf(data,
"Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
@@ -448,7 +451,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
(((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
(unsigned char)socksreq[1]);
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_IDENTD;
case 93:
failf(data,
"Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
@@ -458,7 +461,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
(((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
(unsigned char)socksreq[1]);
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_IDENTD_DIFFER;
default:
failf(data,
"Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
@@ -467,24 +470,24 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
(((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
(unsigned char)socksreq[1]);
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_UNKNOWN_FAIL;
}
*done = TRUE;
- return CURLE_OK; /* Proxy was successful! */
+ return CURLPX_OK; /* Proxy was successful! */
}
/*
* This function logs in to a SOCKS5 proxy and sends the specifics to the final
* destination server.
*/
-CURLcode Curl_SOCKS5(const char *proxy_user,
- const char *proxy_password,
- const char *hostname,
- int remote_port,
- int sockindex,
- struct connectdata *conn,
- bool *done)
+CURLproxycode Curl_SOCKS5(const char *proxy_user,
+ const char *proxy_password,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn,
+ bool *done)
{
/*
According to the RFC1928, section "6. Replies". This is what a SOCK5
@@ -561,13 +564,13 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
result = Curl_write_plain(conn, sockfd, (char *)socksreq, idx, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Unable to send initial SOCKS5 request.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_SEND_CONNECT;
}
if(written != idx) {
sxstate(conn, CONNECT_SOCKS_SEND);
sx->outstanding = idx - written;
sx->outp = &socksreq[written];
- return CURLE_OK;
+ return CURLPX_OK;
}
sxstate(conn, CONNECT_SOCKS_READ);
goto CONNECT_SOCKS_READ_INIT;
@@ -576,13 +579,13 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
sx->outstanding, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Unable to send initial SOCKS5 request.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_SEND_CONNECT;
}
if(written != sx->outstanding) {
/* not done, remain in state */
sx->outstanding -= written;
sx->outp += written;
- return CURLE_OK;
+ return CURLPX_OK;
}
/* FALLTHROUGH */
CONNECT_SOCKS_READ_INIT:
@@ -595,22 +598,22 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Unable to receive initial SOCKS5 response.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_RECV_CONNECT;
}
else if(!result && !actualread) {
/* connection closed */
failf(data, "Connection to proxy closed");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_CLOSED;
}
else if(actualread != sx->outstanding) {
/* remain in reading state */
sx->outstanding -= actualread;
sx->outp += actualread;
- return CURLE_OK;
+ return CURLPX_OK;
}
else if(socksreq[0] != 5) {
failf(data, "Received invalid version in initial SOCKS5 response.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_BAD_VERSION;
}
else if(socksreq[1] == 0) {
/* DONE! No authentication needed. Send request. */
@@ -628,7 +631,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
result = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
if(result) {
failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_GSSAPI;
}
}
#endif
@@ -637,16 +640,16 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
if(!allow_gssapi && (socksreq[1] == 1)) {
failf(data,
"SOCKS5 GSSAPI per-message authentication is not supported.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_GSSAPI_PERMSG;
}
else if(socksreq[1] == 255) {
failf(data, "No authentication method was acceptable.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_NO_AUTH;
}
}
failf(data,
"Undocumented SOCKS5 mode attempted to be used by server.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_UNKNOWN_MODE;
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
case CONNECT_GSSAPI_INIT:
/* GSSAPI stuff done non-blocking */
@@ -683,7 +686,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
/* the length must fit in a single byte */
if(proxy_user_len >= 255) {
failf(data, "Excessive user name length for proxy auth");
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ return CURLPX_LONG_USER;
}
memcpy(socksreq + len, proxy_user, proxy_user_len);
}
@@ -693,7 +696,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
/* the length must fit in a single byte */
if(proxy_password_len > 255) {
failf(data, "Excessive password length for proxy auth");
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ return CURLPX_LONG_PASSWD;
}
memcpy(socksreq + len, proxy_password, proxy_password_len);
}
@@ -708,13 +711,13 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
sx->outstanding, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to send SOCKS5 sub-negotiation request.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_SEND_AUTH;
}
if(sx->outstanding != written) {
/* remain in state */
sx->outstanding -= written;
sx->outp += written;
- return CURLE_OK;
+ return CURLPX_OK;
}
sx->outp = socksreq;
sx->outstanding = 2;
@@ -725,24 +728,24 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_RECV_AUTH;
}
else if(!result && !actualread) {
/* connection closed */
failf(data, "connection to proxy closed");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_CLOSED;
}
else if(actualread != sx->outstanding) {
/* remain in state */
sx->outstanding -= actualread;
sx->outp += actualread;
- return CURLE_OK;
+ return CURLPX_OK;
}
/* ignore the first (VER) byte */
else if(socksreq[1] != 0) { /* status */
failf(data, "User was rejected by the SOCKS5 server (%d %d).",
socksreq[0], socksreq[1]);
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_USER_REJECTED;
}
/* Everything is good so far, user was authenticated! */
@@ -755,11 +758,11 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
FALSE, &dns);
if(rc == CURLRESOLV_ERROR)
- return CURLE_COULDNT_RESOLVE_HOST;
+ return CURLPX_RESOLVE_HOST;
if(rc == CURLRESOLV_PENDING) {
sxstate(conn, CONNECT_RESOLVING);
- return CURLE_OK;
+ return CURLPX_OK;
}
sxstate(conn, CONNECT_RESOLVED);
goto CONNECT_RESOLVED;
@@ -768,7 +771,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
case CONNECT_RESOLVING:
/* check if we have the name resolved by now */
- dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
+ dns = Curl_fetch_addr(conn, hostname, remote_port);
if(dns) {
#ifdef CURLRES_ASYNCH
@@ -780,8 +783,11 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
if(!dns) {
result = Curl_resolv_check(data->conn, &dns);
- if(!dns)
- return result;
+ if(!dns) {
+ if(result)
+ return CURLPX_RESOLVE_HOST;
+ return CURLPX_OK;
+ }
}
/* FALLTHROUGH */
CONNECT_RESOLVED:
@@ -793,7 +799,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
if(!hp) {
failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
hostname);
- return CURLE_COULDNT_RESOLVE_HOST;
+ return CURLPX_RESOLVE_HOST;
}
Curl_printable_address(hp, dest, sizeof(dest));
@@ -867,7 +873,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
if(conn->socks5_gssapi_enctype) {
failf(data, "SOCKS5 GSS-API protection not yet implemented.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_GSSAPI_PROTECTION;
}
#endif
sx->outp = socksreq;
@@ -879,18 +885,18 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
sx->outstanding, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to send SOCKS5 connect request.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_SEND_REQUEST;
}
if(sx->outstanding != written) {
/* remain in state */
sx->outstanding -= written;
sx->outp += written;
- return CURLE_OK;
+ return CURLPX_OK;
}
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
if(conn->socks5_gssapi_enctype) {
failf(data, "SOCKS5 GSS-API protection not yet implemented.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_GSSAPI_PROTECTION;
}
#endif
sx->outstanding = 10; /* minimum packet size is 10 */
@@ -902,29 +908,46 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to receive SOCKS5 connect request ack.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_RECV_REQACK;
}
else if(!result && !actualread) {
/* connection closed */
failf(data, "connection to proxy closed");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_CLOSED;
}
else if(actualread != sx->outstanding) {
/* remain in state */
sx->outstanding -= actualread;
sx->outp += actualread;
- return CURLE_OK;
+ return CURLPX_OK;
}
if(socksreq[0] != 5) { /* version */
failf(data,
"SOCKS5 reply has wrong version, version should be 5.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_BAD_VERSION;
}
else if(socksreq[1] != 0) { /* Anything besides 0 is an error */
+ CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
+ int code = socksreq[1];
failf(data, "Can't complete SOCKS5 connection to %s. (%d)",
hostname, (unsigned char)socksreq[1]);
- return CURLE_COULDNT_CONNECT;
+ if(code < 9) {
+ /* RFC 1928 section 6 lists: */
+ static const CURLproxycode lookup[] = {
+ CURLPX_OK,
+ CURLPX_REPLY_GENERAL_SERVER_FAILURE,
+ CURLPX_REPLY_NOT_ALLOWED,
+ CURLPX_REPLY_NETWORK_UNREACHABLE,
+ CURLPX_REPLY_HOST_UNREACHABLE,
+ CURLPX_REPLY_CONNECTION_REFUSED,
+ CURLPX_REPLY_TTL_EXPIRED,
+ CURLPX_REPLY_COMMAND_NOT_SUPPORTED,
+ CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED,
+ };
+ rc = lookup[code];
+ }
+ return rc;
}
/* Fix: in general, returned BND.ADDR is variable length parameter by RFC
@@ -958,7 +981,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
}
else {
failf(data, "SOCKS5 reply has wrong address type.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_BAD_ADDRESS_TYPE;
}
/* At this point we already read first 10 bytes */
@@ -984,25 +1007,25 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to receive SOCKS5 connect request ack.");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_RECV_ADDRESS;
}
else if(!result && !actualread) {
/* connection closed */
failf(data, "connection to proxy closed");
- return CURLE_COULDNT_CONNECT;
+ return CURLPX_CLOSED;
}
else if(actualread != sx->outstanding) {
/* remain in state */
sx->outstanding -= actualread;
sx->outp += actualread;
- return CURLE_OK;
+ return CURLPX_OK;
}
sxstate(conn, CONNECT_DONE);
}
infof(data, "SOCKS5 request granted.\n");
*done = TRUE;
- return CURLE_OK; /* Proxy was successful! */
+ return CURLPX_OK; /* Proxy was successful! */
}
#endif /* CURL_DISABLE_PROXY */