CURLE_PROXY: new error code

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
This commit is contained in:
Daniel Stenberg 2020-08-24 08:39:29 +02:00
parent d71ac6711a
commit 88b1ca7cba
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
15 changed files with 318 additions and 95 deletions

View File

@ -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

View File

@ -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), "

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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)
/*

View File

@ -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:

View File

@ -1134,6 +1134,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 */
};

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>