diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 11f54381a0..60a2b59e56 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -1601,14 +1601,10 @@ static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data) cf->conn->sock[cf->sockindex] = ctx->sock; set_local_ip(cf, data); if(cf->sockindex == FIRSTSOCKET) { - cf->conn->primary = ctx->ip; #ifdef USE_IPV6 cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6); #endif } - else { - cf->conn->secondary = ctx->ip; - } ctx->active = TRUE; } diff --git a/lib/cfilters.c b/lib/cfilters.c index 069d6a24a3..a57aeef55d 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -439,6 +439,29 @@ CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data, return CURLE_RECV_ERROR; } +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static CURLcode cf_verboseconnect(struct Curl_easy *data, + struct Curl_cfilter *cf) +{ + if(Curl_trc_is_verbose(data)) { + struct ip_quadruple ipquad; + int is_ipv6; + CURLcode result; + + result = Curl_conn_cf_get_ip_info(cf, data, &is_ipv6, &ipquad); + if(result) + return result; + + infof(data, "Established %sconnection to %s (%s port %u) from %s port %u ", + (cf->sockindex == SECONDARYSOCKET) ? "2nd " : "", + CURL_CONN_HOST_DISPNAME(data->conn), + ipquad.remote_ip, ipquad.remote_port, + ipquad.local_ip, ipquad.local_port); + } + return CURLE_OK; +} +#endif + CURLcode Curl_conn_connect(struct Curl_easy *data, int sockindex, bool blocking, @@ -482,7 +505,9 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, cf_cntrl_update_info(data, data->conn); conn_report_connect_stats(data, data->conn); data->conn->keepalive = curlx_now(); - Curl_verboseconnect(data, data->conn, sockindex); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + result = cf_verboseconnect(data, cf); +#endif goto out; } else if(result) { @@ -593,6 +618,14 @@ bool Curl_conn_get_ssl_info(struct Curl_easy *data, return FALSE; } +CURLcode Curl_conn_get_ip_info(struct Curl_easy *data, + struct connectdata *conn, int sockindex, + int *is_ipv6, struct ip_quadruple *ipquad) +{ + struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; + return Curl_conn_cf_get_ip_info(cf, data, is_ipv6, ipquad); +} + bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex) { struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; diff --git a/lib/cfilters.h b/lib/cfilters.h index d468e5ad85..74a79da78b 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -404,6 +404,10 @@ bool Curl_conn_get_ssl_info(struct Curl_easy *data, struct connectdata *conn, int sockindex, struct curl_tlssessioninfo *info); +CURLcode Curl_conn_get_ip_info(struct Curl_easy *data, + struct connectdata *conn, int sockindex, + int *is_ipv6, struct ip_quadruple *ipquad); + /** * Connection provides multiplexing of easy handles at `socketindex`. */ diff --git a/lib/connect.c b/lib/connect.c index 35de2946a5..473ec23108 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -405,12 +405,12 @@ typedef enum { } cf_connect_state; struct cf_he_ctx { - int transport; cf_ip_connect_create *cf_create; cf_connect_state state; struct eyeballer *baller[2]; struct eyeballer *winner; struct curltime started; + int transport; }; /* when there are more than one IP address left to use, this macro returns how @@ -629,7 +629,6 @@ static CURLcode is_connected(struct Curl_cfilter *cf, struct curltime now; size_t i; int ongoing, not_started; - const char *hostname; /* Check if any of the conn->tempsock we use for establishing connections * succeeded and, if so, close any ongoing other ones. @@ -748,23 +747,34 @@ evaluate: } } + { + const char *hostname, *proxy_name = NULL; + int port; #ifndef CURL_DISABLE_PROXY - if(conn->bits.socksproxy) - hostname = conn->socks_proxy.host.name; - else if(conn->bits.httpproxy) - hostname = conn->http_proxy.host.name; - else + if(conn->bits.socksproxy) + proxy_name = conn->socks_proxy.host.name; + else if(conn->bits.httpproxy) + proxy_name = conn->http_proxy.host.name; #endif - if(conn->bits.conn_to_host) - hostname = conn->conn_to_host.name; - else - hostname = conn->host.name; + hostname = conn->bits.conn_to_host ? + conn->conn_to_host.name : conn->host.name; - failf(data, "Failed to connect to %s port %u after " - "%" FMT_TIMEDIFF_T " ms: %s", - hostname, conn->primary.remote_port, - curlx_timediff(now, data->progress.t_startsingle), - curl_easy_strerror(result)); + if(cf->sockindex == SECONDARYSOCKET) + port = conn->secondary_port; + else if(cf->conn->bits.conn_to_port) + port = conn->conn_to_port; + else + port = conn->remote_port; + + failf(data, "Failed to connect to %s port %u %s%s%safter " + "%" FMT_TIMEDIFF_T " ms: %s", + hostname, port, + proxy_name ? "via " : "", + proxy_name ? proxy_name : "", + proxy_name ? " " : "", + curlx_timediff(now, data->progress.t_startsingle), + curl_easy_strerror(result)); + } #ifdef SOCKETIMEDOUT if(SOCKETIMEDOUT == data->state.os_errno) diff --git a/lib/ftp.c b/lib/ftp.c index 2fc76c8d08..88eaf18ed3 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -1793,17 +1793,23 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data, } -static char *control_address(struct connectdata *conn) +static char *control_address_dup(struct Curl_easy *data, + struct connectdata *conn) { + struct ip_quadruple ipquad; + int is_ipv6; + /* Returns the control connection IP address. If a proxy tunnel is used, returns the original hostname instead, because the effective control connection address is the proxy address, not the ftp host. */ #ifndef CURL_DISABLE_PROXY if(conn->bits.tunnel_proxy || conn->bits.socksproxy) - return conn->host.name; + return strdup(conn->host.name); #endif - return conn->primary.remote_ip; + if(!Curl_conn_get_ip_info(data, data->conn, FIRSTSOCKET, &is_ipv6, &ipquad)) + return strdup(ipquad.remote_ip); + return NULL; } static bool match_pasv_6nums(const char *p, @@ -1856,7 +1862,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, return CURLE_FTP_WEIRD_PASV_REPLY; } ftpc->newport = (unsigned short)num; - ftpc->newhost = strdup(control_address(conn)); + ftpc->newhost = control_address_dup(data, conn); if(!ftpc->newhost) return CURLE_OUT_OF_MEMORY; } @@ -1900,7 +1906,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, infof(data, "Skip %u.%u.%u.%u for data connection, reuse %s instead", ip[0], ip[1], ip[2], ip[3], conn->host.name); - ftpc->newhost = strdup(control_address(conn)); + ftpc->newhost = control_address_dup(data, conn); } else ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); @@ -1921,17 +1927,26 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, #ifndef CURL_DISABLE_PROXY if(conn->bits.proxy) { - /* + /* * This connection uses a proxy and we need to connect to the proxy again * here. We do not want to rely on a former host lookup that might've * expired now, instead we remake the lookup here and now! */ + struct ip_quadruple ipquad; + int is_ipv6; const char * const host_name = conn->bits.socksproxy ? conn->socks_proxy.host.name : conn->http_proxy.host.name; - (void)Curl_resolv_blocking(data, host_name, conn->primary.remote_port, - conn->ip_version, &dns); + + result = Curl_conn_get_ip_info(data, data->conn, FIRSTSOCKET, + &is_ipv6, &ipquad); + if(result) + return result; + + (void)Curl_resolv_blocking(data, host_name, ipquad.remote_port, + is_ipv6 ? CURL_IPRESOLVE_V6 : CURL_IPRESOLVE_V4, + &dns); /* we connect to the proxy's port */ - connectport = (unsigned short)conn->primary.remote_port; + connectport = (unsigned short)ipquad.remote_port; if(!dns) { failf(data, "cannot resolve proxy host %s:%hu", host_name, connectport); @@ -1947,7 +1962,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, /* postponed address resolution in case of tcp fastopen */ if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) { free(ftpc->newhost); - ftpc->newhost = strdup(control_address(conn)); + ftpc->newhost = control_address_dup(data, conn); if(!ftpc->newhost) return CURLE_OUT_OF_MEMORY; } diff --git a/lib/http.c b/lib/http.c index c3f9d4e9b0..8c5a8a7178 100644 --- a/lib/http.c +++ b/lib/http.c @@ -2674,6 +2674,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) const char *p_accept; /* Accept: string */ unsigned char httpversion; const char *alpn; + const char *info_version = NULL; /* Always consider the DO phase done after this function call, even if there may be parts of the request that are not yet sent, since we can deal with @@ -2682,6 +2683,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) alpn = Curl_conn_get_alpn_negotiated(data, conn); if(alpn && !strcmp("h3", alpn)) { DEBUGASSERT(Curl_conn_http_version(data, conn) == 30); + info_version = "HTTP/3"; } else if(alpn && !strcmp("h2", alpn)) { #ifndef CURL_DISABLE_PROXY @@ -2694,7 +2696,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) } else #endif - DEBUGASSERT(Curl_conn_http_version(data, conn) == 20); + DEBUGASSERT(Curl_conn_http_version(data, conn) == 20); + info_version = "HTTP/2"; } else { /* Check if user wants to use HTTP/2 with clear TCP */ @@ -2703,9 +2706,15 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) result = Curl_http2_switch(data); if(result) goto fail; + info_version = "HTTP/2"; } + else + info_version = "HTTP/1.x"; } + if(info_version && !data->conn->bits.reuse) + infof(data, "using %s", info_version); + /* Add collecting of headers written to client. For a new connection, * we might have done that already, but reuse * or multiplex needs it here as well. */ diff --git a/lib/ldap.c b/lib/ldap.c index bcf53856b6..de5a309755 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -335,6 +335,8 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) #endif char *user = NULL; char *passwd = NULL; + struct ip_quadruple ipquad; + int is_ipv6; *done = TRUE; /* unconditionally */ infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d", @@ -352,6 +354,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) goto quit; } + result = Curl_conn_get_ip_info(data, conn, FIRSTSOCKET, &is_ipv6, &ipquad); + if(result) + goto quit; + /* Get the URL scheme (either ldap or ldaps) */ if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) ldap_ssl = 1; @@ -383,7 +389,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) #ifdef HAVE_LDAP_SSL #ifdef USE_WIN32_LDAP /* Win32 LDAP SDK does not support insecure mode without CA! */ - server = ldap_sslinit(host, (curl_ldap_num_t)conn->primary.remote_port, 1); + server = ldap_sslinit(host, (curl_ldap_num_t)ipquad.remote_port, 1); ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); #else int ldap_option; @@ -422,10 +428,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) result = CURLE_SSL_CERTPROBLEM; goto quit; } - server = ldap_init(host, conn->primary.remote_port); + server = ldap_init(host, ipquad.remote_port); if(!server) { failf(data, "LDAP local: Cannot connect to %s:%u", - conn->host.dispname, conn->primary.remote_port); + conn->host.dispname, ipquad.remote_port); result = CURLE_COULDNT_CONNECT; goto quit; } @@ -465,10 +471,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) goto quit; } else { - server = ldap_init(host, (curl_ldap_num_t)conn->primary.remote_port); + server = ldap_init(host, (curl_ldap_num_t)ipquad.remote_port); if(!server) { failf(data, "LDAP local: Cannot connect to %s:%u", - conn->host.dispname, conn->primary.remote_port); + conn->host.dispname, ipquad.remote_port); result = CURLE_COULDNT_CONNECT; goto quit; } diff --git a/lib/socks.c b/lib/socks.c index 66c3a601a8..fea5c50cdd 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -1139,7 +1139,21 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, result = connect_SOCKS(cf, sx, data); if(!result && sx->state == CONNECT_DONE) { cf->connected = TRUE; - Curl_verboseconnect(data, conn, cf->sockindex); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(Curl_trc_is_verbose(data)) { + struct ip_quadruple ipquad; + int is_ipv6; + result = Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad); + if(result) + return result; + infof(data, "Opened %sSOCKS connection from %s port %u to %s port %u " + "(via %s port %u)", + (sockindex == SECONDARYSOCKET) ? "2nd " : "", + ipquad.local_ip, ipquad.local_port, + sx->hostname, sx->remote_port, + ipquad.remote_ip, ipquad.remote_port); + } +#endif socks_proxy_cf_free(cf); } diff --git a/lib/url.c b/lib/url.c index 204f380137..33d3b4018a 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1384,36 +1384,6 @@ ConnectionExists(struct Curl_easy *data, return result; } -/* - * verboseconnect() displays verbose information after a connect - */ -#ifndef CURL_DISABLE_VERBOSE_STRINGS -void Curl_verboseconnect(struct Curl_easy *data, - struct connectdata *conn, int sockindex) -{ - if(data->set.verbose && sockindex == SECONDARYSOCKET) - infof(data, "Connected 2nd connection to %s port %u", - conn->secondary.remote_ip, conn->secondary.remote_port); - else - infof(data, "Connected to %s (%s) port %u", - CURL_CONN_HOST_DISPNAME(conn), conn->primary.remote_ip, - conn->primary.remote_port); -#ifndef CURL_DISABLE_HTTP - if(conn->handler->protocol & PROTO_FAMILY_HTTP) { - const char *alpn = Curl_conn_get_alpn_negotiated(data, conn); - if(!alpn || !strcmp("http/1.1", alpn) || !strcmp("http/1.0", alpn)) - infof(data, "using HTTP/1.x"); - else if(!strcmp("h2", alpn)) - infof(data, "using HTTP/2"); - else if(!strcmp("h3", alpn)) - infof(data, "using HTTP/3"); - else - infof(data, "using ALPN protocol '%s'", alpn); - } -#endif -} -#endif - /* * Allocate and initialize a new connectdata object. */ @@ -1430,7 +1400,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->sockfd = CURL_SOCKET_BAD; conn->writesockfd = CURL_SOCKET_BAD; conn->connection_id = -1; /* no ID */ - conn->primary.remote_port = -1; /* unknown at this point */ conn->remote_port = -1; /* unknown at this point */ /* Default protocol-independent behavior does not support persistent @@ -2042,7 +2011,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, valid = FALSE; } if(valid) - conn->primary.remote_port = conn->remote_port = (unsigned short)port; + conn->remote_port = (unsigned short)port; } (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0); @@ -2118,16 +2087,11 @@ static CURLcode setup_connection_internals(struct Curl_easy *data, p = conn->handler; /* May have changed. */ } - if(conn->primary.remote_port < 0) - /* we check for -1 here since if proxy was detected already, this was - likely already set to the proxy port */ - conn->primary.remote_port = p->defport; - /* Now create the destination name */ #ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { hostname = conn->http_proxy.host.name; - port = conn->primary.remote_port; + port = conn->http_proxy.port; } else #endif @@ -2388,12 +2352,8 @@ static CURLcode parse_proxy(struct Curl_easy *data, port = CURL_DEFAULT_PROXY_PORT; } } - if(port >= 0) { + if(port >= 0) proxyinfo->port = port; - if(conn->primary.remote_port < 0 || sockstype || - !conn->socks_proxy.host.rawalloc) - conn->primary.remote_port = port; - } /* now, clone the proxy hostname */ uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE); @@ -3302,6 +3262,7 @@ static CURLcode resolve_server(struct Curl_easy *data, struct Curl_dns_entry **pdns) { struct hostname *ehost; + int eport; timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); const char *peertype = "host"; CURLcode result; @@ -3331,6 +3292,8 @@ static CURLcode resolve_server(struct Curl_easy *data, if(CONN_IS_PROXIED(conn)) { ehost = conn->bits.socksproxy ? &conn->socks_proxy.host : &conn->http_proxy.host; + eport = conn->bits.socksproxy ? conn->socks_proxy.port : + conn->http_proxy.port; peertype = "proxy"; } else @@ -3339,8 +3302,7 @@ static CURLcode resolve_server(struct Curl_easy *data, ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host; /* If not connecting via a proxy, extract the port from the URL, if it is * there, thus overriding any defaults that might have been set above. */ - conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port; + eport = conn->bits.conn_to_port ? conn->conn_to_port : conn->remote_port; } /* Resolve target host right on */ @@ -3349,7 +3311,7 @@ static CURLcode resolve_server(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; result = Curl_resolv_timeout(data, conn->hostname_resolve, - conn->primary.remote_port, conn->ip_version, + eport, conn->ip_version, pdns, timeout_ms); DEBUGASSERT(!result || !*pdns); if(result == CURLE_AGAIN) { diff --git a/lib/url.h b/lib/url.h index 92747335d8..11a69d4157 100644 --- a/lib/url.h +++ b/lib/url.h @@ -79,13 +79,6 @@ const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme, #define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless specified */ -#ifdef CURL_DISABLE_VERBOSE_STRINGS -#define Curl_verboseconnect(x,y,z) Curl_nop_stmt -#else -void Curl_verboseconnect(struct Curl_easy *data, struct connectdata *conn, - int sockindex); -#endif - /** * Return TRUE iff the given connection is considered dead. * @param nowp NULL or pointer to time being checked against. diff --git a/lib/urldata.h b/lib/urldata.h index fffc38a614..0d48afe915 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -674,14 +674,6 @@ struct connectdata { struct proxy_info socks_proxy; struct proxy_info http_proxy; #endif - /* 'primary' and 'secondary' get filled with IP quadruple - (local/remote numerical ip address and port) whenever a connect is - *attempted*. - When more than one address is tried for a connection these will hold data - for the last attempt. When the connection is actually established - these are updated with data which comes directly from the socket. */ - struct ip_quadruple primary; - struct ip_quadruple secondary; char *user; /* username string, allocated */ char *passwd; /* password string, allocated */ char *options; /* options string, allocated */ diff --git a/tests/http/testenv/vsftpd.py b/tests/http/testenv/vsftpd.py index 38aacd99a0..0819861c62 100644 --- a/tests/http/testenv/vsftpd.py +++ b/tests/http/testenv/vsftpd.py @@ -221,4 +221,4 @@ class VsFTPD: def get_data_ports(self, r: ExecResult) -> List[int]: return [int(m.group(1)) for line in r.trace_lines if - (m := re.match(r'.*Connected 2nd connection to .* port (\d+)', line))] + (m := re.match(r'.*Established 2nd connection to .* \(\S+ port (\d+)\)', line))]