connectdata: remove primary+secondary ip_quadruple

Since the content varies during connection setup and while doing it
(eyeballing), remove these strcut from `connectdata` and replace use
with querying the connection filters. Those keep that information
already.

Change the info logging of established connections to also give the
local address and port.

Closes #17960
This commit is contained in:
Stefan Eissing 2025-07-18 13:18:44 +02:00 committed by Daniel Stenberg
parent 450c00f983
commit 83da4d9d3b
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
13 changed files with 152 additions and 125 deletions

View File

@ -72,7 +72,7 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
CURLcode result;
const char *client_ip;
struct ip_quadruple ipquad;
int is_ipv6;
bool is_ipv6;
DEBUGASSERT(ctx);
DEBUGASSERT(ctx->state == HAPROXY_INIT);

View File

@ -1600,15 +1600,10 @@ static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
/* use this socket from now on */
cf->conn->sock[cf->sockindex] = ctx->sock;
set_local_ip(cf, data);
if(cf->sockindex == FIRSTSOCKET) {
cf->conn->primary = ctx->ip;
#ifdef USE_IPV6
#ifdef USE_IPV6
if(cf->sockindex == FIRSTSOCKET)
cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6);
#endif
}
else {
cf->conn->secondary = ctx->ip;
}
#endif
ctx->active = TRUE;
}

View File

@ -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;
bool 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,
bool *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;
@ -841,11 +874,15 @@ cf_get_remote_addr(struct Curl_cfilter *cf, struct Curl_easy *data)
CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
struct Curl_easy *data,
int *is_ipv6, struct ip_quadruple *ipquad)
bool *is_ipv6, struct ip_quadruple *ipquad)
{
if(cf)
return cf->cft->query(cf, data, CF_QUERY_IP_INFO, is_ipv6, ipquad);
return CURLE_UNKNOWN_OPTION;
CURLcode result = CURLE_UNKNOWN_OPTION;
if(cf) {
int ipv6 = 0;
result = cf->cft->query(cf, data, CF_QUERY_IP_INFO, &ipv6, ipquad);
*is_ipv6 = !!ipv6;
}
return result;
}
curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)

View File

@ -345,7 +345,7 @@ curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
struct Curl_easy *data,
int *is_ipv6, struct ip_quadruple *ipquad);
bool *is_ipv6, struct ip_quadruple *ipquad);
bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
struct Curl_easy *data);
@ -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,
bool *is_ipv6, struct ip_quadruple *ipquad);
/**
* Connection provides multiplexing of easy handles at `socketindex`.
*/

View File

@ -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)
@ -990,7 +1000,7 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
#ifndef CURL_DISABLE_VERBOSE_STRINGS
if(Curl_trc_cf_is_verbose(cf, data)) {
struct ip_quadruple ipquad;
int is_ipv6;
bool is_ipv6;
if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) {
const char *host;
int port;

View File

@ -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;
bool 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, 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,24 @@ 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
/* 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!
*/
* expired now, instead we remake the lookup here and now! */
struct ip_quadruple ipquad;
bool 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 +1960,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;
}

View File

@ -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,19 +2683,20 @@ 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
if((Curl_conn_http_version(data, conn) != 20) &&
conn->bits.proxy && !conn->bits.tunnel_proxy
) {
conn->bits.proxy && !conn->bits.tunnel_proxy) {
result = Curl_http2_switch(data);
if(result)
goto fail;
}
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 +2705,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. */

View File

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

View File

@ -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;
bool 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);
}

View File

@ -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);
@ -2101,33 +2070,21 @@ static CURLcode setup_range(struct Curl_easy *data)
static CURLcode setup_connection_internals(struct Curl_easy *data,
struct connectdata *conn)
{
const struct Curl_handler *p;
const char *hostname;
int port;
CURLcode result;
/* Perform setup complement if some. */
p = conn->handler;
if(p->setup_connection) {
result = (*p->setup_connection)(data, conn);
if(conn->handler->setup_connection) {
result = conn->handler->setup_connection(data, conn);
if(result)
return result;
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 +2345,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 +3255,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 +3285,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 +3295,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 +3304,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) {

View File

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

View File

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

View File

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