summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2013-10-26 20:19:27 +0200
committerDaniel Stenberg <daniel@haxx.se>2013-10-26 23:33:06 +0200
commitd44b0142714041b784ffd10792318674ecb1ed56 (patch)
treecad83bbb4196769983345ddf8eb310f9f39f8ca0
parent469b42335076b15ccfed1db411d3fadca699c39c (diff)
downloadcurl-d44b0142714041b784ffd10792318674ecb1ed56.tar.gz
FTP: make the data connection work when going through proxy
This is a regression since the switch to always-multi internally c43127414d89c. Test 1316 was modified since we now clearly call the Curl_client_write() function when doing the LIST transfer part and then the handler->protocol says FTP and ftpc.transfertype is 'A' which implies text converting even though that the response is initially a HTTP CONNECT response in this case.
-rw-r--r--lib/connect.c2
-rw-r--r--lib/ftp.c184
-rw-r--r--lib/ftp.h6
-rw-r--r--lib/socks.c4
-rw-r--r--lib/url.c9
-rw-r--r--lib/url.h2
-rw-r--r--tests/data/test13166
7 files changed, 119 insertions, 94 deletions
diff --git a/lib/connect.c b/lib/connect.c
index 2b5719d12..c442c48f8 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -777,7 +777,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 e818af6c5..487f9d5a4 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1802,6 +1802,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->req.protop;
+ memset(&http_proxy, 0, sizeof(http_proxy));
+ data->req.protop = &http_proxy;
+
+ result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
+
+ data->req.protop = 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)
{
@@ -1812,13 +1885,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) &&
@@ -1851,7 +1918,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 ||
@@ -1860,10 +1927,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
@@ -1916,14 +1984,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,82 +2059,21 @@ 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);
+ ftp_pasv_verbose(conn, conninfo, ftpc->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->req.protop;
- memset(&http_proxy, 0, sizeof(http_proxy));
- data->req.protop = &http_proxy;
-
- result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
-
- data->req.protop = 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;
conn->bits.do_more = TRUE;
state(conn, FTP_STOP); /* this phase is completed */
@@ -3625,6 +3633,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 bdd59c93d..b6bfc0287 100644
--- a/lib/ftp.h
+++ b/lib/ftp.h
@@ -147,6 +147,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 b101a0de4..d7136c605 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 c1672d08b..9973bd273 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -3219,9 +3219,12 @@ 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)
+ 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) {
@@ -3281,7 +3284,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 418413c48..cd46a92c3 100644
--- a/lib/url.h
+++ b/lib/url.h
@@ -70,7 +70,7 @@ void Curl_close_connections(struct SessionHandle *data);
#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
diff --git a/tests/data/test1316 b/tests/data/test1316
index 51f58c268..cdf434d5b 100644
--- a/tests/data/test1316
+++ b/tests/data/test1316
@@ -25,9 +25,9 @@ Magic: sure you can FTP me
HTTP/1.1 200 Mighty fine indeed
Magic: sure you can FTP me
-HTTP/1.1 200 Mighty fine indeed
-Magic: sure you can FTP me
-
+HTTP/1.1 200 Mighty fine indeed
+Magic: sure you can FTP me
+
total 20
drwxr-xr-x 8 98 98 512 Oct 22 13:06 .
drwxr-xr-x 8 98 98 512 Oct 22 13:06 ..