You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
850 lines
30 KiB
850 lines
30 KiB
6 years ago
|
From bf2eb071494dd48bf1730ce2bc7d21a8fd13b5c8 Mon Sep 17 00:00:00 2001
|
||
|
From: Daniel Stenberg <daniel@haxx.se>
|
||
|
Date: Sat, 26 Oct 2013 20:19:27 +0200
|
||
|
Subject: [PATCH 1/7] FTP: make the data connection work when going through
|
||
|
proxy
|
||
|
|
||
|
This is a regression since the switch to always-multi internally
|
||
|
c43127414d89c.
|
||
|
|
||
|
Upstream-commit: d44b0142714041b784ffd10792318674ecb1ed56
|
||
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
||
|
---
|
||
|
lib/connect.c | 2 +-
|
||
|
lib/ftp.c | 183 +++++++++++++++++++++++++++++++---------------------------
|
||
|
lib/ftp.h | 6 ++
|
||
|
lib/socks.c | 4 ++
|
||
|
lib/url.c | 9 ++-
|
||
|
lib/url.h | 2 +-
|
||
|
6 files changed, 117 insertions(+), 89 deletions(-)
|
||
|
|
||
|
diff --git a/lib/connect.c b/lib/connect.c
|
||
|
index 5aa53fe..78627e6 100644
|
||
|
--- a/lib/connect.c
|
||
|
+++ b/lib/connect.c
|
||
|
@@ -715,7 +715,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||
|
/* we are connected with TCP, awesome! */
|
||
|
|
||
|
/* see if we need to do any proxy magic first once we connected */
|
||
|
- code = Curl_connected_proxy(conn);
|
||
|
+ code = Curl_connected_proxy(conn, sockindex);
|
||
|
if(code)
|
||
|
return code;
|
||
|
|
||
|
diff --git a/lib/ftp.c b/lib/ftp.c
|
||
|
index 63d1e64..b9fa12e 100644
|
||
|
--- a/lib/ftp.c
|
||
|
+++ b/lib/ftp.c
|
||
|
@@ -1800,6 +1800,79 @@ static CURLcode ftp_epsv_disable(struct connectdata *conn)
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * Perform the necessary magic that needs to be done once the TCP connection
|
||
|
+ * to the proxy has completed.
|
||
|
+ */
|
||
|
+static CURLcode proxy_magic(struct connectdata *conn,
|
||
|
+ char *newhost, unsigned short newport,
|
||
|
+ bool *magicdone)
|
||
|
+{
|
||
|
+ struct SessionHandle *data=conn->data;
|
||
|
+ CURLcode result;
|
||
|
+
|
||
|
+ *magicdone = FALSE;
|
||
|
+ switch(conn->proxytype) {
|
||
|
+ case CURLPROXY_SOCKS5:
|
||
|
+ case CURLPROXY_SOCKS5_HOSTNAME:
|
||
|
+ result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost,
|
||
|
+ newport, SECONDARYSOCKET, conn);
|
||
|
+ *magicdone = TRUE;
|
||
|
+ break;
|
||
|
+ case CURLPROXY_SOCKS4:
|
||
|
+ result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
|
||
|
+ SECONDARYSOCKET, conn, FALSE);
|
||
|
+ *magicdone = TRUE;
|
||
|
+ break;
|
||
|
+ case CURLPROXY_SOCKS4A:
|
||
|
+ result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
|
||
|
+ SECONDARYSOCKET, conn, TRUE);
|
||
|
+ *magicdone = TRUE;
|
||
|
+ break;
|
||
|
+ case CURLPROXY_HTTP:
|
||
|
+ case CURLPROXY_HTTP_1_0:
|
||
|
+ /* do nothing here. handled later. */
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ failf(data, "unknown proxytype option given");
|
||
|
+ result = CURLE_COULDNT_CONNECT;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
|
||
|
+ /* BLOCKING */
|
||
|
+ /* We want "seamless" FTP operations through HTTP proxy tunnel */
|
||
|
+
|
||
|
+ /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
|
||
|
+ * member conn->proto.http; we want FTP through HTTP and we have to
|
||
|
+ * change the member temporarily for connecting to the HTTP proxy. After
|
||
|
+ * Curl_proxyCONNECT we have to set back the member to the original
|
||
|
+ * struct FTP pointer
|
||
|
+ */
|
||
|
+ struct HTTP http_proxy;
|
||
|
+ struct FTP *ftp_save = data->state.proto.ftp;
|
||
|
+ memset(&http_proxy, 0, sizeof(http_proxy));
|
||
|
+ data->state.proto.http = &http_proxy;
|
||
|
+
|
||
|
+ result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
|
||
|
+
|
||
|
+ data->state.proto.ftp = ftp_save;
|
||
|
+
|
||
|
+ if(result)
|
||
|
+ return result;
|
||
|
+
|
||
|
+ if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
|
||
|
+ /* the CONNECT procedure is not complete, the tunnel is not yet up */
|
||
|
+ state(conn, FTP_STOP); /* this phase is completed */
|
||
|
+ conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ *magicdone = TRUE;
|
||
|
+ }
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||
|
int ftpcode)
|
||
|
{
|
||
|
@@ -1810,13 +1883,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||
|
struct Curl_dns_entry *addr=NULL;
|
||
|
int rc;
|
||
|
unsigned short connectport; /* the local port connect() should use! */
|
||
|
- unsigned short newport=0; /* remote port */
|
||
|
bool connected;
|
||
|
-
|
||
|
- /* newhost must be able to hold a full IP-style address in ASCII, which
|
||
|
- in the IPv6 case means 5*8-1 = 39 letters */
|
||
|
-#define NEWHOST_BUFSIZE 48
|
||
|
- char newhost[NEWHOST_BUFSIZE];
|
||
|
char *str=&data->state.buffer[4]; /* start on the first letter */
|
||
|
|
||
|
if((ftpc->count1 == 0) &&
|
||
|
@@ -1849,7 +1916,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||
|
return CURLE_FTP_WEIRD_PASV_REPLY;
|
||
|
}
|
||
|
if(ptr) {
|
||
|
- newport = (unsigned short)(num & 0xffff);
|
||
|
+ ftpc->newport = (unsigned short)(num & 0xffff);
|
||
|
|
||
|
if(conn->bits.tunnel_proxy ||
|
||
|
conn->proxytype == CURLPROXY_SOCKS5 ||
|
||
|
@@ -1858,10 +1925,11 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||
|
conn->proxytype == CURLPROXY_SOCKS4A)
|
||
|
/* proxy tunnel -> use other host info because ip_addr_str is the
|
||
|
proxy address not the ftp host */
|
||
|
- snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
|
||
|
+ snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
|
||
|
+ conn->host.name);
|
||
|
else
|
||
|
/* use the same IP we are already connected to */
|
||
|
- snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
|
||
|
+ snprintf(ftpc->newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
@@ -1914,14 +1982,15 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||
|
conn->proxytype == CURLPROXY_SOCKS4A)
|
||
|
/* proxy tunnel -> use other host info because ip_addr_str is the
|
||
|
proxy address not the ftp host */
|
||
|
- snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
|
||
|
+ snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s", conn->host.name);
|
||
|
else
|
||
|
- snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
|
||
|
+ snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
|
||
|
+ conn->ip_addr_str);
|
||
|
}
|
||
|
else
|
||
|
- snprintf(newhost, sizeof(newhost),
|
||
|
+ snprintf(ftpc->newhost, sizeof(ftpc->newhost),
|
||
|
"%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
|
||
|
- newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
|
||
|
+ ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
|
||
|
}
|
||
|
else if(ftpc->count1 == 0) {
|
||
|
/* EPSV failed, move on to PASV */
|
||
|
@@ -1957,15 +2026,15 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||
|
}
|
||
|
else {
|
||
|
/* normal, direct, ftp connection */
|
||
|
- rc = Curl_resolv(conn, newhost, newport, &addr);
|
||
|
+ rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
|
||
|
if(rc == CURLRESOLV_PENDING)
|
||
|
/* BLOCKING */
|
||
|
(void)Curl_resolver_wait_resolv(conn, &addr);
|
||
|
|
||
|
- connectport = newport; /* we connect to the remote port */
|
||
|
+ connectport = ftpc->newport; /* we connect to the remote port */
|
||
|
|
||
|
if(!addr) {
|
||
|
- failf(data, "Can't resolve new host %s:%hu", newhost, connectport);
|
||
|
+ failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
|
||
|
return CURLE_FTP_CANT_GET_HOST;
|
||
|
}
|
||
|
}
|
||
|
@@ -1990,80 +2059,20 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||
|
/*
|
||
|
* When this is used from the multi interface, this might've returned with
|
||
|
* the 'connected' set to FALSE and thus we are now awaiting a non-blocking
|
||
|
- * connect to connect and we should not be "hanging" here waiting.
|
||
|
+ * connect to connect.
|
||
|
*/
|
||
|
|
||
|
if(data->set.verbose)
|
||
|
/* this just dumps information about this second connection */
|
||
|
- ftp_pasv_verbose(conn, conninfo, newhost, connectport);
|
||
|
-
|
||
|
- switch(conn->proxytype) {
|
||
|
- /* FIX: this MUST wait for a proper connect first if 'connected' is
|
||
|
- * FALSE */
|
||
|
- case CURLPROXY_SOCKS5:
|
||
|
- case CURLPROXY_SOCKS5_HOSTNAME:
|
||
|
- result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
|
||
|
- SECONDARYSOCKET, conn);
|
||
|
- connected = TRUE;
|
||
|
- break;
|
||
|
- case CURLPROXY_SOCKS4:
|
||
|
- result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
|
||
|
- SECONDARYSOCKET, conn, FALSE);
|
||
|
- connected = TRUE;
|
||
|
- break;
|
||
|
- case CURLPROXY_SOCKS4A:
|
||
|
- result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
|
||
|
- SECONDARYSOCKET, conn, TRUE);
|
||
|
- connected = TRUE;
|
||
|
- break;
|
||
|
- case CURLPROXY_HTTP:
|
||
|
- case CURLPROXY_HTTP_1_0:
|
||
|
- /* do nothing here. handled later. */
|
||
|
- break;
|
||
|
- default:
|
||
|
- failf(data, "unknown proxytype option given");
|
||
|
- result = CURLE_COULDNT_CONNECT;
|
||
|
- break;
|
||
|
- }
|
||
|
-
|
||
|
- if(result) {
|
||
|
- if(ftpc->count1 == 0 && ftpcode == 229)
|
||
|
- return ftp_epsv_disable(conn);
|
||
|
- return result;
|
||
|
- }
|
||
|
-
|
||
|
- if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
|
||
|
- /* FIX: this MUST wait for a proper connect first if 'connected' is
|
||
|
- * FALSE */
|
||
|
-
|
||
|
- /* BLOCKING */
|
||
|
- /* We want "seamless" FTP operations through HTTP proxy tunnel */
|
||
|
-
|
||
|
- /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
|
||
|
- * conn->proto.http; we want FTP through HTTP and we have to change the
|
||
|
- * member temporarily for connecting to the HTTP proxy. After
|
||
|
- * Curl_proxyCONNECT we have to set back the member to the original struct
|
||
|
- * FTP pointer
|
||
|
- */
|
||
|
- struct HTTP http_proxy;
|
||
|
- struct FTP *ftp_save = data->state.proto.ftp;
|
||
|
- memset(&http_proxy, 0, sizeof(http_proxy));
|
||
|
- data->state.proto.http = &http_proxy;
|
||
|
-
|
||
|
- result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
|
||
|
+ ftp_pasv_verbose(conn, conninfo, ftpc->newhost, connectport);
|
||
|
|
||
|
- data->state.proto.ftp = ftp_save;
|
||
|
-
|
||
|
- if(result)
|
||
|
- return result;
|
||
|
-
|
||
|
- if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
|
||
|
- /* the CONNECT procedure is not complete, the tunnel is not yet up */
|
||
|
- state(conn, FTP_STOP); /* this phase is completed */
|
||
|
- conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
|
||
|
-
|
||
|
- return result;
|
||
|
- }
|
||
|
+ if(connected) {
|
||
|
+ /* Only do the proxy connection magic if we're actually connected. We do
|
||
|
+ this little trick and send in the same 'connected' variable here again
|
||
|
+ and it will be set FALSE by proxy_magic() for when for example the
|
||
|
+ CONNECT procedure doesn't complete */
|
||
|
+ infof(data, "Connection to proxy confirmed almost instantly\n");
|
||
|
+ result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected);
|
||
|
}
|
||
|
|
||
|
conn->bits.tcpconnect[SECONDARYSOCKET] = connected;
|
||
|
@@ -3686,6 +3695,10 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
|
||
|
/* Ready to do more? */
|
||
|
if(connected) {
|
||
|
DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
|
||
|
+ if(conn->bits.proxy) {
|
||
|
+ infof(data, "Connection to proxy confirmed\n");
|
||
|
+ result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected);
|
||
|
+ }
|
||
|
}
|
||
|
else {
|
||
|
if(result && (ftpc->count1 == 0)) {
|
||
|
diff --git a/lib/ftp.h b/lib/ftp.h
|
||
|
index d359f28..4b4a488 100644
|
||
|
--- a/lib/ftp.h
|
||
|
+++ b/lib/ftp.h
|
||
|
@@ -154,6 +154,12 @@ struct ftp_conn {
|
||
|
curl_off_t known_filesize; /* file size is different from -1, if wildcard
|
||
|
LIST parsing was done and wc_statemach set
|
||
|
it */
|
||
|
+ /* newhost must be able to hold a full IP-style address in ASCII, which
|
||
|
+ in the IPv6 case means 5*8-1 = 39 letters */
|
||
|
+#define NEWHOST_BUFSIZE 48
|
||
|
+ char newhost[NEWHOST_BUFSIZE]; /* this is the pair to connect the DATA... */
|
||
|
+ unsigned short newport; /* connection to */
|
||
|
+
|
||
|
};
|
||
|
|
||
|
#define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */
|
||
|
diff --git a/lib/socks.c b/lib/socks.c
|
||
|
index 51bb946..0cf397c 100644
|
||
|
--- a/lib/socks.c
|
||
|
+++ b/lib/socks.c
|
||
|
@@ -129,6 +129,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
|
||
|
|
||
|
curlx_nonblock(sock, FALSE);
|
||
|
|
||
|
+ infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port);
|
||
|
+
|
||
|
/*
|
||
|
* Compose socks4 request
|
||
|
*
|
||
|
@@ -182,6 +184,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
|
||
|
else
|
||
|
hp = NULL; /* fail! */
|
||
|
|
||
|
+ infof(data, "SOCKS4 connect to %s (locally resolved)\n", buf);
|
||
|
+
|
||
|
Curl_resolv_unlock(data, dns); /* not used anymore from now on */
|
||
|
|
||
|
}
|
||
|
diff --git a/lib/url.c b/lib/url.c
|
||
|
index cfc2744..11e0ff5 100644
|
||
|
--- a/lib/url.c
|
||
|
+++ b/lib/url.c
|
||
|
@@ -3103,8 +3103,13 @@ static CURLcode ConnectionStore(struct SessionHandle *data,
|
||
|
Note: this function's sub-functions call failf()
|
||
|
|
||
|
*/
|
||
|
-CURLcode Curl_connected_proxy(struct connectdata *conn)
|
||
|
+CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex)
|
||
|
{
|
||
|
+ if(!conn->bits.proxy || sockindex)
|
||
|
+ /* this magic only works for the primary socket as the secondary is used
|
||
|
+ for FTP only and it has FTP specific magic in ftp.c */
|
||
|
+ return CURLE_OK;
|
||
|
+
|
||
|
switch(conn->proxytype) {
|
||
|
#ifndef CURL_DISABLE_PROXY
|
||
|
case CURLPROXY_SOCKS5:
|
||
|
@@ -3162,7 +3167,7 @@ static CURLcode ConnectPlease(struct SessionHandle *data,
|
||
|
conn->ip_addr = addr;
|
||
|
|
||
|
if(*connected) {
|
||
|
- result = Curl_connected_proxy(conn);
|
||
|
+ result = Curl_connected_proxy(conn, FIRSTSOCKET);
|
||
|
if(!result) {
|
||
|
conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
|
||
|
Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
|
||
|
diff --git a/lib/url.h b/lib/url.h
|
||
|
index c0d9c38..1da9be3 100644
|
||
|
--- a/lib/url.h
|
||
|
+++ b/lib/url.h
|
||
|
@@ -74,7 +74,7 @@ void Curl_reset_reqproto(struct connectdata *conn);
|
||
|
#define CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE "rcmd" /* default socks5 gssapi
|
||
|
service */
|
||
|
|
||
|
-CURLcode Curl_connected_proxy(struct connectdata *conn);
|
||
|
+CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex);
|
||
|
|
||
|
#ifdef CURL_DISABLE_VERBOSE_STRINGS
|
||
|
#define Curl_verboseconnect(x) Curl_nop_stmt
|
||
|
--
|
||
|
2.9.3
|
||
|
|
||
|
|
||
|
From 4157798db51c859a1130203cebf377e77f56398a Mon Sep 17 00:00:00 2001
|
||
|
From: Steve Holme <steve_holme@hotmail.com>
|
||
|
Date: Sun, 27 Oct 2013 00:00:01 +0100
|
||
|
Subject: [PATCH 2/7] ftp: Fixed compiler warning
|
||
|
|
||
|
warning: 'result' may be used uninitialized in this function
|
||
|
|
||
|
Upstream-commit: 9f503a254b0c720706124cb75922a0123f0079f0
|
||
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
||
|
---
|
||
|
lib/ftp.c | 2 +-
|
||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/lib/ftp.c b/lib/ftp.c
|
||
|
index b9fa12e..9c863b9 100644
|
||
|
--- a/lib/ftp.c
|
||
|
+++ b/lib/ftp.c
|
||
|
@@ -1808,8 +1808,8 @@ static CURLcode proxy_magic(struct connectdata *conn,
|
||
|
char *newhost, unsigned short newport,
|
||
|
bool *magicdone)
|
||
|
{
|
||
|
+ CURLcode result = CURLE_OK;
|
||
|
struct SessionHandle *data=conn->data;
|
||
|
- CURLcode result;
|
||
|
|
||
|
*magicdone = FALSE;
|
||
|
switch(conn->proxytype) {
|
||
|
--
|
||
|
2.9.3
|
||
|
|
||
|
|
||
|
From 30566b76d17d9c5e13e3af621ecae0f4cafc3ac8 Mon Sep 17 00:00:00 2001
|
||
|
From: Daniel Stenberg <daniel@haxx.se>
|
||
|
Date: Sat, 19 Jul 2014 23:58:58 +0200
|
||
|
Subject: [PATCH 3/7] CONNECT: Revert Curl_proxyCONNECT back to 7.29.0 design
|
||
|
|
||
|
This reverts commit cb3e6dfa3511 and instead fixes the problem
|
||
|
differently.
|
||
|
|
||
|
The reverted commit addressed a test failure in test 1021 by simplifying
|
||
|
and generalizing the code flow in a way that damaged the
|
||
|
performance. Now we modify the flow so that Curl_proxyCONNECT() again
|
||
|
does as much as possible in one go, yet still do test 1021 with and
|
||
|
without valgrind. It failed due to mistakes in the multi state machine.
|
||
|
|
||
|
Bug: http://curl.haxx.se/bug/view.cgi?id=1397
|
||
|
Reported-by: Paul Saab
|
||
|
|
||
|
Upstream-commit: a4cece3d47cf092da00cf9910e87bb60b9eff533
|
||
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
||
|
---
|
||
|
lib/http_proxy.c | 47 ++++++++++++++++++++++++++++++-----------------
|
||
|
lib/multi.c | 16 ++++++++++------
|
||
|
2 files changed, 40 insertions(+), 23 deletions(-)
|
||
|
|
||
|
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
|
||
|
index c2eb667..d311b89 100644
|
||
|
--- a/lib/http_proxy.c
|
||
|
+++ b/lib/http_proxy.c
|
||
|
@@ -98,8 +98,6 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||
|
struct SessionHandle *data=conn->data;
|
||
|
struct SingleRequest *k = &data->req;
|
||
|
CURLcode result;
|
||
|
- long timeout =
|
||
|
- data->set.timeout?data->set.timeout:PROXY_TIMEOUT; /* in milliseconds */
|
||
|
curl_socket_t tunnelsocket = conn->sock[sockindex];
|
||
|
curl_off_t cl=0;
|
||
|
bool closeConnection = FALSE;
|
||
|
@@ -223,14 +221,25 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||
|
return result;
|
||
|
|
||
|
conn->tunnel_state[sockindex] = TUNNEL_CONNECT;
|
||
|
+ } /* END CONNECT PHASE */
|
||
|
+
|
||
|
+ check = Curl_timeleft(data, NULL, TRUE);
|
||
|
+ if(check <= 0) {
|
||
|
+ failf(data, "Proxy CONNECT aborted due to timeout");
|
||
|
+ return CURLE_RECV_ERROR;
|
||
|
+ }
|
||
|
|
||
|
- /* now we've issued the CONNECT and we're waiting to hear back, return
|
||
|
- and get called again polling-style */
|
||
|
+ if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0))
|
||
|
+ /* return so we'll be called again polling-style */
|
||
|
return CURLE_OK;
|
||
|
+ else {
|
||
|
+ DEBUGF(infof(data,
|
||
|
+ "Read response immediately from proxy CONNECT\n"));
|
||
|
+ }
|
||
|
|
||
|
- } /* END CONNECT PHASE */
|
||
|
+ /* at this point, the tunnel_connecting phase is over. */
|
||
|
|
||
|
- { /* BEGIN NEGOTIATION PHASE */
|
||
|
+ { /* READING RESPONSE PHASE */
|
||
|
size_t nread; /* total size read */
|
||
|
int perline; /* count bytes per line */
|
||
|
int keepon=TRUE;
|
||
|
@@ -247,9 +256,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||
|
|
||
|
while((nread<BUFSIZE) && (keepon && !error)) {
|
||
|
|
||
|
- /* if timeout is requested, find out how much remaining time we have */
|
||
|
- check = timeout - /* timeout time */
|
||
|
- Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
|
||
|
+ check = Curl_timeleft(data, NULL, TRUE);
|
||
|
if(check <= 0) {
|
||
|
failf(data, "Proxy CONNECT aborted due to timeout");
|
||
|
error = SELECT_TIMEOUT; /* already too little time */
|
||
|
@@ -279,6 +286,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||
|
/* proxy auth was requested and there was proxy auth available,
|
||
|
then deem this as "mere" proxy disconnect */
|
||
|
conn->bits.proxy_connect_closed = TRUE;
|
||
|
+ infof(data, "Proxy CONNECT connection closed");
|
||
|
}
|
||
|
else {
|
||
|
error = SELECT_ERROR;
|
||
|
@@ -519,7 +527,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||
|
conn->sock[sockindex] = CURL_SOCKET_BAD;
|
||
|
break;
|
||
|
}
|
||
|
- } /* END NEGOTIATION PHASE */
|
||
|
+ } /* END READING RESPONSE PHASE */
|
||
|
|
||
|
/* If we are supposed to continue and request a new URL, which basically
|
||
|
* means the HTTP authentication is still going on so if the tunnel
|
||
|
@@ -534,13 +542,11 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||
|
} while(data->req.newurl);
|
||
|
|
||
|
if(200 != data->req.httpcode) {
|
||
|
- failf(data, "Received HTTP code %d from proxy after CONNECT",
|
||
|
- data->req.httpcode);
|
||
|
-
|
||
|
- if(closeConnection && data->req.newurl)
|
||
|
+ if(closeConnection && data->req.newurl) {
|
||
|
conn->bits.proxy_connect_closed = TRUE;
|
||
|
-
|
||
|
- if(data->req.newurl) {
|
||
|
+ infof(data, "Connect me again please\n");
|
||
|
+ }
|
||
|
+ else if(data->req.newurl) {
|
||
|
/* this won't be used anymore for the CONNECT so free it now */
|
||
|
free(data->req.newurl);
|
||
|
data->req.newurl = NULL;
|
||
|
@@ -549,7 +555,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||
|
/* to back to init state */
|
||
|
conn->tunnel_state[sockindex] = TUNNEL_INIT;
|
||
|
|
||
|
- return CURLE_RECV_ERROR;
|
||
|
+ if(conn->bits.proxy_connect_closed)
|
||
|
+ /* this is not an error, just part of the connection negotiation */
|
||
|
+ return CURLE_OK;
|
||
|
+ else {
|
||
|
+ failf(data, "Received HTTP code %d from proxy after CONNECT",
|
||
|
+ data->req.httpcode);
|
||
|
+ return CURLE_RECV_ERROR;
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
|
||
|
diff --git a/lib/multi.c b/lib/multi.c
|
||
|
index 0e0bb19..3029fa6 100644
|
||
|
--- a/lib/multi.c
|
||
|
+++ b/lib/multi.c
|
||
|
@@ -1134,11 +1134,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||
|
easy->result = Curl_http_connect(easy->easy_conn, &protocol_connect);
|
||
|
|
||
|
if(easy->easy_conn->bits.proxy_connect_closed) {
|
||
|
- /* reset the error buffer */
|
||
|
- if(data->set.errorbuffer)
|
||
|
- data->set.errorbuffer[0] = '\0';
|
||
|
- data->state.errorbuf = FALSE;
|
||
|
-
|
||
|
+ /* connect back to proxy again */
|
||
|
easy->result = CURLE_OK;
|
||
|
result = CURLM_CALL_MULTI_PERFORM;
|
||
|
multistate(easy, CURLM_STATE_CONNECT);
|
||
|
@@ -1164,7 +1160,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||
|
&protocol_connect);
|
||
|
}
|
||
|
|
||
|
- if(CURLE_OK != easy->result) {
|
||
|
+ if(easy->easy_conn->bits.proxy_connect_closed) {
|
||
|
+ /* connect back to proxy again since it was closed in a proxy CONNECT
|
||
|
+ setup */
|
||
|
+ easy->result = CURLE_OK;
|
||
|
+ result = CURLM_CALL_MULTI_PERFORM;
|
||
|
+ multistate(easy, CURLM_STATE_CONNECT);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ else if(CURLE_OK != easy->result) {
|
||
|
/* failure detected */
|
||
|
/* Just break, the cleaning up is handled all in one place */
|
||
|
disconnect_conn = TRUE;
|
||
|
--
|
||
|
2.9.3
|
||
|
|
||
|
|
||
|
From 6ab9346d63e88ddfb8fd3f509ad350cab24c37f4 Mon Sep 17 00:00:00 2001
|
||
|
From: Daniel Stenberg <daniel@haxx.se>
|
||
|
Date: Wed, 17 Jun 2015 00:30:06 +0200
|
||
|
Subject: [PATCH 4/7] FTP: do the HTTP CONNECT for data connection blocking
|
||
|
|
||
|
** WORK-AROUND **
|
||
|
|
||
|
The introduced non-blocking general behaviour for Curl_proxyCONNECT()
|
||
|
didn't work for the data connection establishment unless it was very
|
||
|
fast. The newly introduced function argument makes it operate in a more
|
||
|
blocking manner, more like it used to work in the past. This blocking
|
||
|
approach is only used when the FTP data connecting through HTTP proxy.
|
||
|
|
||
|
Blocking like this is bad. A better fix would make it work more
|
||
|
asynchronously.
|
||
|
|
||
|
Bug: https://github.com/bagder/curl/issues/278
|
||
|
|
||
|
Upstream-commit: b88f980a7437abc1159a1185c04d381347c8f5b1
|
||
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
||
|
---
|
||
|
lib/ftp.c | 4 ++--
|
||
|
lib/http_proxy.c | 22 ++++++++++++++--------
|
||
|
lib/http_proxy.h | 3 ++-
|
||
|
3 files changed, 18 insertions(+), 11 deletions(-)
|
||
|
|
||
|
diff --git a/lib/ftp.c b/lib/ftp.c
|
||
|
index 63d1e64..db1e29e 100644
|
||
|
--- a/lib/ftp.c
|
||
|
+++ b/lib/ftp.c
|
||
|
@@ -1854,7 +1854,7 @@ static CURLcode proxy_magic(struct connectdata *conn,
|
||
|
memset(&http_proxy, 0, sizeof(http_proxy));
|
||
|
data->state.proto.http = &http_proxy;
|
||
|
|
||
|
- result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
|
||
|
+ result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport, TRUE);
|
||
|
|
||
|
data->state.proto.ftp = ftp_save;
|
||
|
|
||
|
@@ -3685,7 +3685,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
|
||
|
if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
|
||
|
/* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
|
||
|
aren't used so we blank their arguments. TODO: make this nicer */
|
||
|
- result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
|
||
|
+ result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
|
||
|
index d311b89..4ab280f 100644
|
||
|
--- a/lib/http_proxy.c
|
||
|
+++ b/lib/http_proxy.c
|
||
|
@@ -71,7 +71,7 @@ CURLcode Curl_proxy_connect(struct connectdata *conn)
|
||
|
conn->data->state.proto.http = &http_proxy;
|
||
|
conn->bits.close = FALSE;
|
||
|
result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
|
||
|
- conn->host.name, conn->remote_port);
|
||
|
+ conn->host.name, conn->remote_port, FALSE);
|
||
|
conn->data->state.proto.generic = prot_save;
|
||
|
if(CURLE_OK != result)
|
||
|
return result;
|
||
|
@@ -87,12 +87,16 @@ CURLcode Curl_proxy_connect(struct connectdata *conn)
|
||
|
* Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
|
||
|
* function will issue the necessary commands to get a seamless tunnel through
|
||
|
* this proxy. After that, the socket can be used just as a normal socket.
|
||
|
+ *
|
||
|
+ * 'blocking' set to TRUE means that this function will do the entire CONNECT
|
||
|
+ * + response in a blocking fashion. Should be avoided!
|
||
|
*/
|
||
|
|
||
|
CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||
|
int sockindex,
|
||
|
const char *hostname,
|
||
|
- unsigned short remote_port)
|
||
|
+ unsigned short remote_port,
|
||
|
+ bool blocking)
|
||
|
{
|
||
|
int subversion=0;
|
||
|
struct SessionHandle *data=conn->data;
|
||
|
@@ -229,12 +233,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||
|
return CURLE_RECV_ERROR;
|
||
|
}
|
||
|
|
||
|
- if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0))
|
||
|
- /* return so we'll be called again polling-style */
|
||
|
- return CURLE_OK;
|
||
|
- else {
|
||
|
- DEBUGF(infof(data,
|
||
|
- "Read response immediately from proxy CONNECT\n"));
|
||
|
+ if(!blocking) {
|
||
|
+ if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0))
|
||
|
+ /* return so we'll be called again polling-style */
|
||
|
+ return CURLE_OK;
|
||
|
+ else {
|
||
|
+ DEBUGF(infof(data,
|
||
|
+ "Read response immediately from proxy CONNECT\n"));
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
/* at this point, the tunnel_connecting phase is over. */
|
||
|
diff --git a/lib/http_proxy.h b/lib/http_proxy.h
|
||
|
index 518c093..4dddc3b 100644
|
||
|
--- a/lib/http_proxy.h
|
||
|
+++ b/lib/http_proxy.h
|
||
|
@@ -26,7 +26,8 @@
|
||
|
/* ftp can use this as well */
|
||
|
CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||
|
int tunnelsocket,
|
||
|
- const char *hostname, unsigned short remote_port);
|
||
|
+ const char *hostname, unsigned short remote_port,
|
||
|
+ bool blocking);
|
||
|
|
||
|
/* Default proxy timeout in milliseconds */
|
||
|
#define PROXY_TIMEOUT (3600*1000)
|
||
|
--
|
||
|
2.9.3
|
||
|
|
||
|
|
||
|
From 7be64d4d3e1b966d491c6cde4fe3b6d69f03185b Mon Sep 17 00:00:00 2001
|
||
|
From: Kamil Dudka <kdudka@redhat.com>
|
||
|
Date: Thu, 9 Feb 2017 16:21:52 +0100
|
||
|
Subject: [PATCH 5/7] nss: make FTPS work with --proxytunnel
|
||
|
|
||
|
If the NSS code was in the middle of a non-blocking handshake and it
|
||
|
was asked to finish the handshake in blocking mode, it unexpectedly
|
||
|
continued in the non-blocking mode, which caused a FTPS connection
|
||
|
over CONNECT to fail with "(81) Socket not ready for send/recv".
|
||
|
|
||
|
Bug: https://bugzilla.redhat.com/1420327
|
||
|
|
||
|
Upstream-commit: 8fa5409800668ad5305e7517597286014c7708fb
|
||
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
||
|
---
|
||
|
lib/nss.c | 23 +++++++++++------------
|
||
|
1 file changed, 11 insertions(+), 12 deletions(-)
|
||
|
|
||
|
diff --git a/lib/nss.c b/lib/nss.c
|
||
|
index 848ce86..cf45f3a 100644
|
||
|
--- a/lib/nss.c
|
||
|
+++ b/lib/nss.c
|
||
|
@@ -1305,13 +1305,14 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
|
||
|
return curlerr;
|
||
|
}
|
||
|
|
||
|
-/* Switch the SSL socket into non-blocking mode. */
|
||
|
-static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl,
|
||
|
- struct SessionHandle *data)
|
||
|
+/* Switch the SSL socket into blocking or non-blocking mode. */
|
||
|
+static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
|
||
|
+ struct SessionHandle *data,
|
||
|
+ bool blocking)
|
||
|
{
|
||
|
static PRSocketOptionData sock_opt;
|
||
|
sock_opt.option = PR_SockOpt_Nonblocking;
|
||
|
- sock_opt.value.non_blocking = PR_TRUE;
|
||
|
+ sock_opt.value.non_blocking = !blocking;
|
||
|
|
||
|
if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS)
|
||
|
return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
|
||
|
@@ -1615,16 +1616,14 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
|
||
|
/* we do not expect CURLE_AGAIN from nss_setup_connect() */
|
||
|
return rv;
|
||
|
|
||
|
- if(!blocking) {
|
||
|
- /* in non-blocking mode, set NSS non-blocking mode before handshake */
|
||
|
- rv = nss_set_nonblock(connssl, data);
|
||
|
- if(rv)
|
||
|
- return rv;
|
||
|
- }
|
||
|
-
|
||
|
connssl->connecting_state = ssl_connect_2;
|
||
|
}
|
||
|
|
||
|
+ /* enable/disable blocking mode before handshake */
|
||
|
+ rv = nss_set_blocking(connssl, data, blocking);
|
||
|
+ if(rv)
|
||
|
+ return rv;
|
||
|
+
|
||
|
rv = nss_do_connect(conn, sockindex);
|
||
|
switch(rv) {
|
||
|
case CURLE_OK:
|
||
|
@@ -1640,7 +1639,7 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
|
||
|
|
||
|
if(blocking) {
|
||
|
/* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
|
||
|
- rv = nss_set_nonblock(connssl, data);
|
||
|
+ rv = nss_set_blocking(connssl, data, /* blocking */ FALSE);
|
||
|
if(rv)
|
||
|
return rv;
|
||
|
}
|
||
|
--
|
||
|
2.7.4
|
||
|
|
||
|
|
||
|
From 9dbd6550acdc143da0b044ae3b06368a87c8449a Mon Sep 17 00:00:00 2001
|
||
|
From: Kamil Dudka <kdudka@redhat.com>
|
||
|
Date: Mon, 27 Mar 2017 18:00:44 +0200
|
||
|
Subject: [PATCH 6/7] url: plug memory leaks triggered by
|
||
|
curl-7_37_1-19-ga4cece3
|
||
|
|
||
|
---
|
||
|
lib/url.c | 9 +++++++++
|
||
|
1 file changed, 9 insertions(+)
|
||
|
|
||
|
diff --git a/lib/url.c b/lib/url.c
|
||
|
index cfc2744..ed72be1 100644
|
||
|
--- a/lib/url.c
|
||
|
+++ b/lib/url.c
|
||
|
@@ -421,6 +421,7 @@ CURLcode Curl_close(struct SessionHandle *data)
|
||
|
data->state.path = NULL;
|
||
|
|
||
|
Curl_safefree(data->state.proto.generic);
|
||
|
+ Curl_safefree(data->req.newurl);
|
||
|
|
||
|
/* Close down all open SSL info and sessions */
|
||
|
Curl_ssl_close_all(data);
|
||
|
@@ -3923,6 +3924,14 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
|
||
|
const struct Curl_handler * p;
|
||
|
CURLcode result;
|
||
|
|
||
|
+ /* XXX: picked from curl-7_32_0-2-g4ad8e14 */
|
||
|
+ /* in some case in the multi state-machine, we go back to the CONNECT state
|
||
|
+ and then a second (or third or...) call to this function will be made
|
||
|
+ without doing a DISCONNECT or DONE in between (since the connection is
|
||
|
+ yet in place) and therefore this function needs to first make sure
|
||
|
+ there's no lingering previous data allocated. */
|
||
|
+ Curl_safefree(conn->data->req.newurl);
|
||
|
+
|
||
|
conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
|
||
|
|
||
|
/* Scan protocol handler table. */
|
||
|
--
|
||
|
2.9.3
|
||
|
|
||
|
|
||
|
From cfb58b02f5bb78a2f4b17f3bb6ce6acd196b3ec6 Mon Sep 17 00:00:00 2001
|
||
|
From: Kamil Dudka <kdudka@redhat.com>
|
||
|
Date: Tue, 28 Mar 2017 15:50:59 +0200
|
||
|
Subject: [PATCH 7/7] http: do not treat FTPS over CONNECT as HTTPS
|
||
|
|
||
|
If we use FTPS over CONNECT, the TLS handshake for the FTPS control
|
||
|
connection needs to be initiated in the SENDPROTOCONNECT state, not
|
||
|
the WAITPROXYCONNECT state. Otherwise, if the TLS handshake completed
|
||
|
without blocking, the information about the completed TLS handshake
|
||
|
would be saved to a wrong flag. Consequently, the TLS handshake would
|
||
|
be initiated in the SENDPROTOCONNECT state once again on the same
|
||
|
connection, resulting in a failure of the TLS handshake. I was able to
|
||
|
observe the failure with the NSS backend if curl ran through valgrind.
|
||
|
|
||
|
Note that this commit partially reverts curl-7_21_6-52-ge34131d.
|
||
|
|
||
|
Upstream-commit: 2549831daaa3aef394f7b42e750cba1afae35642
|
||
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
||
|
---
|
||
|
lib/http.c | 2 +-
|
||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/lib/http.c b/lib/http.c
|
||
|
index 04beeb1..db37cf9 100644
|
||
|
--- a/lib/http.c
|
||
|
+++ b/lib/http.c
|
||
|
@@ -1310,7 +1310,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
|
||
|
/* nothing else to do except wait right now - we're not done here. */
|
||
|
return CURLE_OK;
|
||
|
|
||
|
- if(conn->given->flags & PROTOPT_SSL) {
|
||
|
+ if(conn->given->protocol & CURLPROTO_HTTPS) {
|
||
|
/* perform SSL initialization */
|
||
|
result = https_connecting(conn, done);
|
||
|
if(result)
|
||
|
--
|
||
|
2.9.3
|
||
|
|