summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2020-08-03 14:07:10 +0200
committerDaniel Stenberg <daniel@haxx.se>2020-08-04 15:57:45 +0200
commit52ad36ddcf0b0eae8c45ed1eac690e474a8782af (patch)
tree27679b9c5d550af908c36579faf5cb450d7d1cc9
parenta1e0b7922a4a54fe9f7487ed71958d346d453a05 (diff)
downloadcurl-bagder/proxy-error.tar.gz
CURLE_PROXY: new error codebagder/proxy-error
Failures clearly returned from a (SOCKS) proxy now causes this return code. Previously the situation was not very clear as what would be returned and when. In addition: when this error code is returned, an application can use CURLINFO_PROXY_ERROR to query libcurl for the detailed error, which then returns a value from the new 'CURLproxycode' enum. Closes #5770
-rw-r--r--docs/libcurl/curl_easy_getinfo.33
-rw-r--r--docs/libcurl/opts/CURLINFO_PROXY_ERROR.3104
-rw-r--r--docs/libcurl/opts/Makefile.inc3
-rw-r--r--docs/libcurl/symbols-in-versions36
-rw-r--r--include/curl/curl.h46
-rw-r--r--lib/connect.c14
-rw-r--r--lib/getinfo.c3
-rw-r--r--lib/socks.c165
-rw-r--r--lib/socks.h26
-rw-r--r--lib/strerror.c3
-rw-r--r--lib/urldata.h1
-rw-r--r--tests/data/test15383
-rw-r--r--tests/data/test7022
-rw-r--r--tests/data/test7032
-rw-r--r--tests/data/test7162
15 files changed, 318 insertions, 95 deletions
diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3
index 27c277965..68c77e5ca 100644
--- a/docs/libcurl/curl_easy_getinfo.3
+++ b/docs/libcurl/curl_easy_getinfo.3
@@ -141,6 +141,9 @@ See \fICURLINFO_REQUEST_SIZE(3)\fP
.IP CURLINFO_SSL_VERIFYRESULT
Certificate verification result.
See \fICURLINFO_SSL_VERIFYRESULT(3)\fP
+.IP CURLINFO_PROXY_ERROR
+Detailed proxy error.
+See \fICURLINFO_PROXY_ERROR(3)\fP
.IP CURLINFO_PROXY_SSL_VERIFYRESULT
Proxy certificate verification result.
See \fICURLINFO_PROXY_SSL_VERIFYRESULT(3)\fP
diff --git a/docs/libcurl/opts/CURLINFO_PROXY_ERROR.3 b/docs/libcurl/opts/CURLINFO_PROXY_ERROR.3
new file mode 100644
index 000000000..c6420b9b3
--- /dev/null
+++ b/docs/libcurl/opts/CURLINFO_PROXY_ERROR.3
@@ -0,0 +1,104 @@
+.\" **************************************************************************
+.\" * _ _ ____ _
+.\" * Project ___| | | | _ \| |
+.\" * / __| | | | |_) | |
+.\" * | (__| |_| | _ <| |___
+.\" * \___|\___/|_| \_\_____|
+.\" *
+.\" * Copyright (C) 1998 - 2020, 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
+.\" * are also available at https://curl.haxx.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
+.\" * furnished to do so, under the terms of the COPYING file.
+.\" *
+.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+.\" * KIND, either express or implied.
+.\" *
+.\" **************************************************************************
+.\"
+.TH CURLINFO_PROXY_ERROR 3 "3 Aug 2020" "libcurl 7.73.0" "curl_easy_getinfo options"
+.SH NAME
+CURLINFO_PROXY_ERROR \- get the detailed (SOCKS) proxy error
+.SH SYNOPSIS
+.nf
+#include <curl/curl.h>
+
+typedef enum {
+ CURLPX_OK,
+ CURLPX_BAD_ADDRESS_TYPE,
+ CURLPX_BAD_VERSION,
+ CURLPX_CLOSED,
+ CURLPX_GSSAPI,
+ CURLPX_GSSAPI_PERMSG,
+ CURLPX_GSSAPI_PROTECTION,
+ CURLPX_IDENTD,
+ CURLPX_IDENTD_DIFFER,
+ CURLPX_LONG_HOSTNAME,
+ CURLPX_LONG_PASSWD,
+ CURLPX_LONG_USER,
+ CURLPX_NO_AUTH,
+ CURLPX_RECV_ADDRESS,
+ CURLPX_RECV_AUTH,
+ CURLPX_RECV_CONNECT,
+ CURLPX_RECV_REQACK,
+ CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED,
+ CURLPX_REPLY_COMMAND_NOT_SUPPORTED,
+ CURLPX_REPLY_CONNECTION_REFUSED,
+ CURLPX_REPLY_GENERAL_SERVER_FAILURE,
+ CURLPX_REPLY_HOST_UNREACHABLE,
+ CURLPX_REPLY_NETWORK_UNREACHABLE,
+ CURLPX_REPLY_NOT_ALLOWED,
+ CURLPX_REPLY_TTL_EXPIRED,
+ CURLPX_REPLY_UNASSIGNED,
+ CURLPX_REQUEST_FAILED,
+ CURLPX_RESOLVE_HOST,
+ CURLPX_SEND_AUTH,
+ CURLPX_SEND_CONNECT,
+ CURLPX_SEND_REQUEST,
+ CURLPX_UNKNOWN_FAIL,
+ CURLPX_UNKNOWN_MODE,
+ CURLPX_USER_REJECTED,
+ CURLPX_LAST /* never use */
+} CURLproxycode;
+
+CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROXY_ERROR, long *detail);
+.fi
+.SH DESCRIPTION
+Pass a pointer to a long to receive a detailed error code when the most recent
+transfer returned a CURLE_PROXY error.
+
+The return value will match the CURLproxycode set.
+
+The returned value will be zero (equal to CURLPX_OK) if no such response code
+was available.
+.SH PROTOCOLS
+All that can be done over SOCKS
+.SH EXAMPLE
+.nf
+CURL *curl = curl_easy_init();
+if(curl) {
+ CURLcode res;
+ curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
+
+ curl_easy_setopt(curl, CURLOPT_PROXY, "socks5://127.0.0.1");
+ res = curl_easy_perform(curl);
+ if(res == CURLE_PROXY) {
+ long proxycode;
+ res = curl_easy_getinfo(curl, CURLINFO_PROXY_ERROR, &proxycode);
+ if(!res && proxycode)
+ printf("The detailed proxy error: %ld\\n", proxycode);
+ }
+ curl_easy_cleanup(curl);
+}
+.fi
+.SH AVAILABILITY
+Added in 7.73.0
+.SH RETURN VALUE
+Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
+.SH "SEE ALSO"
+.BR CURLINFO_RESPONSE_CODE "(3), " libcurl-errors "(3), "
+.BR curl_easy_getinfo "(3), " curl_easy_setopt "(3), "
diff --git a/docs/libcurl/opts/Makefile.inc b/docs/libcurl/opts/Makefile.inc
index 8708f32ed..ebf234002 100644
--- a/docs/libcurl/opts/Makefile.inc
+++ b/docs/libcurl/opts/Makefile.inc
@@ -57,8 +57,9 @@ man_MANS = \
CURLINFO_PRIMARY_PORT.3 \
CURLINFO_PRIVATE.3 \
CURLINFO_PROTOCOL.3 \
- CURLINFO_PROXYAUTH_AVAIL.3 \
+ CURLINFO_PROXY_ERROR.3 \
CURLINFO_PROXY_SSL_VERIFYRESULT.3 \
+ CURLINFO_PROXYAUTH_AVAIL.3 \
CURLINFO_REDIRECT_COUNT.3 \
CURLINFO_REDIRECT_TIME.3 \
CURLINFO_REDIRECT_TIME_T.3 \
diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions
index c0cdbdc04..797e8ab33 100644
--- a/docs/libcurl/symbols-in-versions
+++ b/docs/libcurl/symbols-in-versions
@@ -105,6 +105,7 @@ CURLE_OPERATION_TIMEOUTED 7.1 7.17.0
CURLE_OUT_OF_MEMORY 7.1
CURLE_PARTIAL_FILE 7.1
CURLE_PEER_FAILED_VERIFICATION 7.17.1
+CURLE_PROXY 7.73.0
CURLE_QUIC_CONNECT_ERROR 7.69.0
CURLE_QUOTE_ERROR 7.17.0
CURLE_RANGE_ERROR 7.17.0
@@ -261,6 +262,7 @@ CURLINFO_PRIMARY_PORT 7.21.0
CURLINFO_PRIVATE 7.10.3
CURLINFO_PROTOCOL 7.52.0
CURLINFO_PROXYAUTH_AVAIL 7.10.8
+CURLINFO_PROXY_ERROR 7.73.0
CURLINFO_PROXY_SSL_VERIFYRESULT 7.52.0
CURLINFO_PTR 7.54.1
CURLINFO_REDIRECT_COUNT 7.9.7
@@ -710,6 +712,40 @@ CURLPROXY_SOCKS4 7.10
CURLPROXY_SOCKS4A 7.18.0
CURLPROXY_SOCKS5 7.10
CURLPROXY_SOCKS5_HOSTNAME 7.18.0
+CURLPX_BAD_ADDRESS_TYPE 7.73.0
+CURLPX_BAD_VERSION 7.73.0
+CURLPX_CLOSED 7.73.0
+CURLPX_GSSAPI 7.73.0
+CURLPX_GSSAPI_PERMSG 7.73.0
+CURLPX_GSSAPI_PROTECTION 7.73.0
+CURLPX_IDENTD 7.73.0
+CURLPX_IDENTD_DIFFER 7.73.0
+CURLPX_LONG_HOSTNAME 7.73.0
+CURLPX_LONG_PASSWD 7.73.0
+CURLPX_LONG_USER 7.73.0
+CURLPX_NO_AUTH 7.73.0
+CURLPX_OK 7.73.0
+CURLPX_RECV_ADDRESS 7.73.0
+CURLPX_RECV_AUTH 7.73.0
+CURLPX_RECV_CONNECT 7.73.0
+CURLPX_RECV_REQACK 7.73.0
+CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED 7.73.0
+CURLPX_REPLY_COMMAND_NOT_SUPPORTED 7.73.0
+CURLPX_REPLY_CONNECTION_REFUSED 7.73.0
+CURLPX_REPLY_GENERAL_SERVER_FAILURE 7.73.0
+CURLPX_REPLY_HOST_UNREACHABLE 7.73.0
+CURLPX_REPLY_NETWORK_UNREACHABLE 7.73.0
+CURLPX_REPLY_NOT_ALLOWED 7.73.0
+CURLPX_REPLY_TTL_EXPIRED 7.73.0
+CURLPX_REPLY_UNASSIGNED 7.73.0
+CURLPX_REQUEST_FAILED 7.73.0
+CURLPX_RESOLVE_HOST 7.73.0
+CURLPX_SEND_AUTH 7.73.0
+CURLPX_SEND_CONNECT 7.73.0
+CURLPX_SEND_REQUEST 7.73.0
+CURLPX_UNKNOWN_FAIL 7.73.0
+CURLPX_UNKNOWN_MODE 7.73.0
+CURLPX_USER_REJECTED 7.73.0
CURLSHE_BAD_OPTION 7.10.3
CURLSHE_INVALID 7.10.3
CURLSHE_IN_USE 7.10.3
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 5aeaca91d..f4d5bf645 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -610,6 +610,7 @@ typedef enum {
error */
CURLE_HTTP3, /* 95 - An HTTP/3 layer problem */
CURLE_QUIC_CONNECT_ERROR, /* 96 - QUIC connection error */
+ CURLE_PROXY, /* 97 - proxy handshake error */
CURL_LAST /* never use! */
} CURLcode;
@@ -689,6 +690,48 @@ typedef enum {
#endif /*!CURL_NO_OLDIES*/
+/*
+ * Proxy error codes. Returned in CURLINFO_PROXY_ERROR if CURLE_PROXY was
+ * return for the transfers.
+ */
+typedef enum {
+ CURLPX_OK,
+ CURLPX_BAD_ADDRESS_TYPE,
+ CURLPX_BAD_VERSION,
+ CURLPX_CLOSED,
+ CURLPX_GSSAPI,
+ CURLPX_GSSAPI_PERMSG,
+ CURLPX_GSSAPI_PROTECTION,
+ CURLPX_IDENTD,
+ CURLPX_IDENTD_DIFFER,
+ CURLPX_LONG_HOSTNAME,
+ CURLPX_LONG_PASSWD,
+ CURLPX_LONG_USER,
+ CURLPX_NO_AUTH,
+ CURLPX_RECV_ADDRESS,
+ CURLPX_RECV_AUTH,
+ CURLPX_RECV_CONNECT,
+ CURLPX_RECV_REQACK,
+ CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED,
+ CURLPX_REPLY_COMMAND_NOT_SUPPORTED,
+ CURLPX_REPLY_CONNECTION_REFUSED,
+ CURLPX_REPLY_GENERAL_SERVER_FAILURE,
+ CURLPX_REPLY_HOST_UNREACHABLE,
+ CURLPX_REPLY_NETWORK_UNREACHABLE,
+ CURLPX_REPLY_NOT_ALLOWED,
+ CURLPX_REPLY_TTL_EXPIRED,
+ CURLPX_REPLY_UNASSIGNED,
+ CURLPX_REQUEST_FAILED,
+ CURLPX_RESOLVE_HOST,
+ CURLPX_SEND_AUTH,
+ CURLPX_SEND_CONNECT,
+ CURLPX_SEND_REQUEST,
+ CURLPX_UNKNOWN_FAIL,
+ CURLPX_UNKNOWN_MODE,
+ CURLPX_USER_REJECTED,
+ CURLPX_LAST /* never use */
+} CURLproxycode;
+
/* This prototype applies to all conversion callbacks */
typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
@@ -2643,8 +2686,9 @@ typedef enum {
CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56,
CURLINFO_RETRY_AFTER = CURLINFO_OFF_T + 57,
CURLINFO_EFFECTIVE_METHOD = CURLINFO_STRING + 58,
+ CURLINFO_PROXY_ERROR = CURLINFO_LONG + 59,
- CURLINFO_LASTONE = 58
+ CURLINFO_LASTONE = 59
} CURLINFO;
/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
diff --git a/lib/connect.c b/lib/connect.c
index 313c23315..24524401f 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -746,8 +746,8 @@ static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
bool *done)
{
CURLcode result = CURLE_OK;
-
#ifndef CURL_DISABLE_PROXY
+ CURLproxycode pxresult = CURLPX_OK;
if(conn->bits.socksproxy) {
/* for the secondary socket (FTP), use the "connect to host"
* but ignore the "connect to port" (use the secondary port)
@@ -767,20 +767,24 @@ static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
switch(conn->socks_proxy.proxytype) {
case CURLPROXY_SOCKS5:
case CURLPROXY_SOCKS5_HOSTNAME:
- result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
- host, port, sockindex, conn, done);
+ pxresult = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
+ host, port, sockindex, conn, done);
break;
case CURLPROXY_SOCKS4:
case CURLPROXY_SOCKS4A:
- result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
- conn, done);
+ pxresult = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
+ conn, done);
break;
default:
failf(conn->data, "unknown proxytype option given");
result = CURLE_COULDNT_CONNECT;
} /* switch proxytype */
+ if(pxresult) {
+ result = CURLE_PROXY;
+ conn->data->info.pxcode = pxresult;
+ }
}
else
#else
diff --git a/lib/getinfo.c b/lib/getinfo.c
index 82691dcc7..49e79e476 100644
--- a/lib/getinfo.c
+++ b/lib/getinfo.c
@@ -269,6 +269,9 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
/* Return the local port of the most recent (primary) connection */
*param_longp = data->info.conn_local_port;
break;
+ case CURLINFO_PROXY_ERROR:
+ *param_longp = (long)data->info.pxcode;
+ break;
case CURLINFO_CONDITION_UNMET:
if(data->info.httpcode == 304)
*param_longp = 1L;
diff --git a/lib/socks.c b/lib/socks.c
index 44783d015..a41b67d5a 100644
--- a/lib/socks.c
+++ b/lib/socks.c
@@ -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;
@@ -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 */
diff --git a/lib/socks.h b/lib/socks.h
index 64a756337..17e6f4610 100644
--- a/lib/socks.h
+++ b/lib/socks.h
@@ -48,24 +48,24 @@ int Curl_SOCKS_getsock(struct connectdata *conn,
* This function logs in to a SOCKS4(a) proxy and sends the specifics to the
* final destination server.
*/
-CURLcode Curl_SOCKS4(const char *proxy_name,
- const char *hostname,
- int remote_port,
- int sockindex,
- struct connectdata *conn,
- bool *done);
+CURLproxycode Curl_SOCKS4(const char *proxy_name,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn,
+ bool *done);
/*
* This function logs in to a SOCKS5 proxy and sends the specifics to the
* final destination server.
*/
-CURLcode Curl_SOCKS5(const char *proxy_name,
- const char *proxy_password,
- const char *hostname,
- int remote_port,
- int sockindex,
- struct connectdata *conn,
- bool *done);
+CURLproxycode Curl_SOCKS5(const char *proxy_name,
+ const char *proxy_password,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn,
+ bool *done);
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
/*
diff --git a/lib/strerror.c b/lib/strerror.c
index 015e588cf..5893f49a9 100644
--- a/lib/strerror.c
+++ b/lib/strerror.c
@@ -320,6 +320,9 @@ curl_easy_strerror(CURLcode error)
case CURLE_QUIC_CONNECT_ERROR:
return "QUIC connection error";
+ case CURLE_PROXY:
+ return "proxy handshake error";
+
/* error codes not used by current libcurl */
case CURLE_OBSOLETE20:
case CURLE_OBSOLETE24:
diff --git a/lib/urldata.h b/lib/urldata.h
index 332ffb392..b9666cd26 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1135,6 +1135,7 @@ struct PureInfo {
OpenSSL, GnuTLS, Schannel, NSS and GSKit
builds. Asked for with CURLOPT_CERTINFO
/ CURLINFO_CERTINFO */
+ CURLproxycode pxcode;
BIT(timecond); /* set to TRUE if the time condition didn't match, which
thus made the document NOT get fetched */
};
diff --git a/tests/data/test1538 b/tests/data/test1538
index ea8eddbb8..03481d56e 100644
--- a/tests/data/test1538
+++ b/tests/data/test1538
@@ -129,7 +129,8 @@ e93: API function called from within callback
e94: An authentication function returned an error
e95: HTTP/3 error
e96: QUIC connection error
-e97: Unknown error
+e97: proxy handshake error
+e98: Unknown error
m-1: Please call curl_multi_perform() soon
m0: No error
m1: Invalid multi handle
diff --git a/tests/data/test702 b/tests/data/test702
index 1c18d0976..dd84ffe26 100644
--- a/tests/data/test702
+++ b/tests/data/test702
@@ -38,7 +38,7 @@ Attempt connect to non-listening HTTP server via SOCKS4 proxy
# Verify data after the test has been "shot"
<verify>
<errorcode>
-7
+97
</errorcode>
</verify>
</testcase>
diff --git a/tests/data/test703 b/tests/data/test703
index d7be71393..3c3487aee 100644
--- a/tests/data/test703
+++ b/tests/data/test703
@@ -38,7 +38,7 @@ Attempt connect to non-listening HTTP server via SOCKS5 proxy
# Verify data after the test has been "shot"
<verify>
<errorcode>
-7
+97
</errorcode>
</verify>
</testcase>
diff --git a/tests/data/test716 b/tests/data/test716
index 96167de5c..531e272fa 100644
--- a/tests/data/test716
+++ b/tests/data/test716
@@ -39,7 +39,7 @@ http://hohoho.example.com:99/716 -x socks5://AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
# Verify data after the test has been "shot"
<verify>
<errorcode>
-43
+97
</errorcode>
</verify>
</testcase>