From 2f8d0df085519351dbd7123178895ba910d756c1 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sat, 18 Feb 2017 13:56:56 +0100 Subject: [PATCH] proxy: fix hostname resolution and IDN conversion Properly resolve, convert and log the proxy host names. Support the "--connect-to" feature for SOCKS proxies and for passive FTP data transfers. Follow-up to cb4e2be Reported-by: Jay Satiro Fixes https://github.com/curl/curl/issues/1248 --- lib/http_proxy.c | 13 ++++--- lib/multi.c | 9 +++-- lib/url.c | 36 ++++++++++--------- lib/urldata.h | 2 -- tests/data/Makefile.inc | 4 +-- tests/data/test2055 | 80 +++++++++++++++++++++++++++++++++++++++++ tests/data/test712 | 1 - tests/data/test713 | 49 +++++++++++++++++++++++++ tests/data/test714 | 64 +++++++++++++++++++++++++++++++++ tests/data/test715 | 66 ++++++++++++++++++++++++++++++++++ 10 files changed, 295 insertions(+), 29 deletions(-) create mode 100755 tests/data/test2055 create mode 100755 tests/data/test713 create mode 100755 tests/data/test714 create mode 100755 tests/data/test715 diff --git a/lib/http_proxy.c b/lib/http_proxy.c index d523ba519..7fde11dbb 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -98,16 +98,21 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex) * original pointer * * This function might be called several times in the multi interface case - * if the proxy's CONNTECT response is not instant. + * if the proxy's CONNECT response is not instant. */ prot_save = conn->data->req.protop; memset(&http_proxy, 0, sizeof(http_proxy)); conn->data->req.protop = &http_proxy; connkeep(conn, "HTTP proxy CONNECT"); - if(sockindex == SECONDARYSOCKET) - hostname = conn->secondaryhostname; - else if(conn->bits.conn_to_host) + + /* for the secondary socket (FTP), use the "connect to host" + * but ignore the "connect to port" (use the secondary port) + */ + + if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; + else if(sockindex == SECONDARYSOCKET) + hostname = conn->secondaryhostname; else hostname = conn->host.name; diff --git a/lib/multi.c b/lib/multi.c index 950b600cb..04bf3f937 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -638,7 +638,10 @@ static CURLcode multi_done(struct connectdata **connp, infof(data, "Connection #%ld to host %s left intact\n", conn->connection_id, - conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); + conn->bits.socksproxy ? conn->socks_proxy.host.dispname : + conn->bits.httpproxy ? conn->http_proxy.host.dispname : + conn->bits.conn_to_host ? conn->conn_to_host.dispname : + conn->host.dispname); } else data->state.lastconnect = NULL; @@ -1477,8 +1480,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, struct connectdata *conn = data->easy_conn; const char *hostname; - if(conn->bits.proxy) - hostname = conn->proxy.name; + if(conn->bits.httpproxy) + hostname = conn->http_proxy.host.name; else if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else diff --git a/lib/url.c b/lib/url.c index 8d1c0cc7f..2886abec8 100644 --- a/lib/url.c +++ b/lib/url.c @@ -3054,7 +3054,6 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) free_fixed_hostname(&conn->host); free_fixed_hostname(&conn->conn_to_host); - free_fixed_hostname(&conn->proxy); free_fixed_hostname(&conn->http_proxy.host); free_fixed_hostname(&conn->socks_proxy.host); @@ -3819,17 +3818,19 @@ CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex) if(conn->bits.socksproxy) { #ifndef CURL_DISABLE_PROXY - const char * const host = conn->bits.conn_to_host ? - conn->conn_to_host.name : - conn->bits.httpproxy ? + /* for the secondary socket (FTP), use the "connect to host" + * but ignore the "connect to port" (use the secondary port) + */ + const char * const host = conn->bits.httpproxy ? conn->http_proxy.host.name : + conn->bits.conn_to_host ? + conn->conn_to_host.name : sockindex == SECONDARYSOCKET ? conn->secondaryhostname : conn->host.name; - const int port = conn->bits.conn_to_port ? conn->conn_to_port : - conn->bits.httpproxy ? - (int)conn->http_proxy.port : - sockindex == SECONDARYSOCKET ? - conn->secondary_port : conn->remote_port; + const int port = conn->bits.httpproxy ? (int)conn->http_proxy.port : + sockindex == SECONDARYSOCKET ? conn->secondary_port : + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port; conn->bits.socksproxy_connecting = TRUE; switch(conn->socks_proxy.proxytype) { case CURLPROXY_SOCKS5: @@ -3867,7 +3868,8 @@ void Curl_verboseconnect(struct connectdata *conn) infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n", conn->bits.socksproxy ? conn->socks_proxy.host.dispname : conn->bits.httpproxy ? conn->http_proxy.host.dispname : - conn->host.dispname, + conn->bits.conn_to_host ? conn->conn_to_host.dispname : + conn->host.dispname, conn->ip_addr_str, conn->port, conn->connection_id); } #endif @@ -4114,7 +4116,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->tempsock[1] = CURL_SOCKET_BAD; /* no file descriptor */ conn->connection_id = -1; /* no ID */ conn->port = -1; /* unknown at this point */ - conn->remote_port = -1; /* unknown */ + conn->remote_port = -1; /* unknown at this point */ #if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD) conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ @@ -5925,7 +5927,7 @@ static CURLcode resolve_server(struct Curl_easy *data, if(conn->bits.conn_to_port) conn->port = conn->conn_to_port; else - conn->port = conn->remote_port; /* it is the same port */ + conn->port = conn->remote_port; /* Resolve target host right on */ rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port, @@ -5981,11 +5983,9 @@ static void reuse_conn(struct connectdata *old_conn, { free_fixed_hostname(&old_conn->http_proxy.host); free_fixed_hostname(&old_conn->socks_proxy.host); - free_fixed_hostname(&old_conn->proxy); free(old_conn->http_proxy.host.rawalloc); free(old_conn->socks_proxy.host.rawalloc); - free(old_conn->proxy.rawalloc); /* free the SSL config struct from this connection struct as this was allocated in vain and is targeted for destruction */ @@ -6432,12 +6432,14 @@ static CURLcode create_conn(struct Curl_easy *data, fix_hostname(conn, &conn->host); if(conn->bits.conn_to_host) fix_hostname(conn, &conn->conn_to_host); - if(conn->proxy.name && *conn->proxy.name) - fix_hostname(conn, &conn->proxy); + if(conn->bits.httpproxy) + fix_hostname(conn, &conn->http_proxy.host); + if(conn->bits.socksproxy) + fix_hostname(conn, &conn->socks_proxy.host); /************************************************************* * Check whether the host and the "connect to host" are equal. - * Do this after the hostnames have been IDN-fixed . + * Do this after the hostnames have been IDN-fixed. *************************************************************/ if(conn->bits.conn_to_host && strcasecompare(conn->conn_to_host.name, conn->host.name)) { diff --git a/lib/urldata.h b/lib/urldata.h index e37b566a5..c17e42cc0 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -936,7 +936,6 @@ struct connectdata { char *secondaryhostname; /* secondary socket host name (ftp) */ struct hostname conn_to_host; /* the host to connect to. valid only if bits.conn_to_host is set */ - struct hostname proxy; struct proxy_info socks_proxy; struct proxy_info http_proxy; @@ -1644,7 +1643,6 @@ struct UserDefined { struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */ struct ssl_general_config general_ssl; /* general user defined SSL stuff */ curl_proxytype proxytype; /* what kind of proxy that is in use */ - curl_proxytype socks_proxytype; /* what kind of socks proxy that is in use */ long dns_cache_timeout; /* DNS cache timeout */ long buffer_size; /* size of receive buffer to use */ void *private_data; /* application-private data */ diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc index 953916d97..33dce05d8 100644 --- a/tests/data/Makefile.inc +++ b/tests/data/Makefile.inc @@ -80,7 +80,7 @@ test626 test627 test628 test629 test630 test631 test632 test633 test634 \ test635 test636 test637 test638 test639 test640 test641 \ \ test700 test701 test702 test703 test704 test705 test706 test707 test708 \ -test709 test710 test711 test712 \ +test709 test710 test711 test712 test713 test714 test715 \ \ test800 test801 test802 test803 test804 test805 test806 test807 test808 \ test809 test810 test811 test812 test813 test814 test815 test816 test817 \ @@ -176,4 +176,4 @@ test2016 test2017 test2018 test2019 test2020 test2021 test2022 test2023 \ test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \ test2032 test2033 test2034 test2035 test2036 test2037 test2038 test2039 \ test2040 test2041 test2042 test2043 test2044 test2045 test2046 test2047 \ -test2048 test2049 test2050 test2051 test2052 test2053 test2054 +test2048 test2049 test2050 test2051 test2052 test2053 test2054 test2055 diff --git a/tests/data/test2055 b/tests/data/test2055 new file mode 100755 index 000000000..cca44942f --- /dev/null +++ b/tests/data/test2055 @@ -0,0 +1,80 @@ + + + +HTTP +HTTP GET +HTTP CONNECT +HTTP proxy +proxytunnel +CURLOPT_CONNECT_TO +SOCKS5 + + + +# +# Server-side + + +HTTP/1.1 200 Connection established + + + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Content-Length: 3 +Content-Type: text/plain + +OK + + + +HTTP/1.1 200 Connection established + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Content-Length: 3 +Content-Type: text/plain + +OK + + + +# +# Client-side + + +http +http-proxy +socks5 + + +Connect to specific host via SOCKS proxy and HTTP proxy (switch to tunnel mode automatically) + + + +http://www.example.com.2055/2055 --connect-to ::connect.example.com.2055:%HTTPPORT -x %HOSTIP:%PROXYPORT --preproxy socks5://%HOSTIP:%SOCKSPORT + + + +# +# Verify data after the test has been "shot" + + +^User-Agent:.* + + +CONNECT connect.example.com.2055:%HTTPPORT HTTP/1.1 +Host: connect.example.com.2055:%HTTPPORT +Proxy-Connection: Keep-Alive + + + +GET /2055 HTTP/1.1 +Host: www.example.com.2055 +Accept: */* + + + + + diff --git a/tests/data/test712 b/tests/data/test712 index c62e9f2c5..252c9ef0e 100644 --- a/tests/data/test712 +++ b/tests/data/test712 @@ -6,7 +6,6 @@ FTP PASV RETR SOCKS5 -all_proxy # diff --git a/tests/data/test713 b/tests/data/test713 new file mode 100755 index 000000000..bb79994f5 --- /dev/null +++ b/tests/data/test713 @@ -0,0 +1,49 @@ + +#based off test 712 + + +FTP +PASV +RETR +SOCKS5 +CURLOPT_CONNECT_TO + + +# +# Server-side + + +silly content + + + +# +# Client-side + + +ftp +socks5 + + +FTP fetch with --proxy set to socks5:// and with --connect-to + + +ftp://ftp.example.com/713 --connect-to ::%HOSTIP:%FTPPORT --proxy socks5://%HOSTIP:%SOCKSPORT + + + +# +# Verify data after the test has been "shot" + + +USER anonymous +PASS ftp@example.com +PWD +EPSV +TYPE I +SIZE 713 +RETR 713 +QUIT + + + diff --git a/tests/data/test714 b/tests/data/test714 new file mode 100755 index 000000000..9d1f0a96e --- /dev/null +++ b/tests/data/test714 @@ -0,0 +1,64 @@ + +#based off test 712 + + +FTP +PASV +RETR +HTTP +HTTP CONNECT +proxytunnel +CURLOPT_CONNECT_TO + + +# +# Server-side + + +HTTP/1.1 200 Connection established + + + + +silly content + + + +HTTP/1.1 200 Connection established + +HTTP/1.1 200 Connection established + +silly content + + + +# +# Client-side + + +ftp +http-proxy + + +FTP fetch with --proxy set to http:// and with --connect-to + + +ftp://ftp.example.com.714/714 --connect-to ::connect.example.com.714:%FTPPORT --proxytunnel --proxy http://%HOSTIP:%PROXYPORT + + + +# +# Verify data after the test has been "shot" + + +USER anonymous +PASS ftp@example.com +PWD +EPSV +TYPE I +SIZE 714 +RETR 714 +QUIT + + + diff --git a/tests/data/test715 b/tests/data/test715 new file mode 100755 index 000000000..ffcfc7e3e --- /dev/null +++ b/tests/data/test715 @@ -0,0 +1,66 @@ + +#based off test 712 + + +FTP +PASV +RETR +HTTP +HTTP CONNECT +proxytunnel +SOCKS5 +CURLOPT_CONNECT_TO + + +# +# Server-side + + +HTTP/1.1 200 Connection established + + + + +silly content + + + +HTTP/1.1 200 Connection established + +HTTP/1.1 200 Connection established + +silly content + + + +# +# Client-side + + +ftp +http-proxy +socks5 + + +FTP fetch with --preproxy, --proxy and --connect-to + + +ftp://ftp.example.com.715/715 --connect-to ::connect.example.com.715:%FTPPORT --proxytunnel --proxy %HOSTIP:%PROXYPORT --preproxy socks5://%HOSTIP:%SOCKSPORT + + + +# +# Verify data after the test has been "shot" + + +USER anonymous +PASS ftp@example.com +PWD +EPSV +TYPE I +SIZE 715 +RETR 715 +QUIT + + +