ftp: check errors on remote ip for data connection

Obtaining the remote ip of the control connection to be used for the
data connection can fail. Check that and fail the transfer when that
does not work.

Triggered by an OSS-Fuzz issue.
Closes #19185
This commit is contained in:
Stefan Eissing 2025-10-22 10:00:53 +02:00 committed by Daniel Stenberg
parent f8ba00fe9d
commit 9c313b61b4
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2

View file

@ -1771,23 +1771,32 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data,
}
static char *control_address_dup(struct Curl_easy *data,
struct connectdata *conn)
static CURLcode ftp_control_addr_dup(struct Curl_easy *data,
struct ftp_conn *ftpc)
{
struct ip_quadruple ipquad;
bool is_ipv6;
struct connectdata *conn = data->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. */
free(ftpc->newhost);
#ifndef CURL_DISABLE_PROXY
if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
return strdup(conn->host.name);
ftpc->newhost = strdup(conn->host.name);
else
#endif
if(!Curl_conn_get_ip_info(data, conn, FIRSTSOCKET, &is_ipv6, &ipquad))
return strdup(ipquad.remote_ip);
return NULL;
if(!Curl_conn_get_ip_info(data, conn, FIRSTSOCKET, &is_ipv6, &ipquad) &&
*ipquad.remote_ip)
ftpc->newhost = strdup(ipquad.remote_ip);
else {
/* failed to get the remote_ip of the DATA connection */
failf(data, "unable to get peername of DATA connection");
return CURLE_FAILED_INIT;
}
return ftpc->newhost ? CURLE_OK : CURLE_OUT_OF_MEMORY;
}
static bool match_pasv_6nums(const char *p,
@ -1840,9 +1849,9 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
return CURLE_FTP_WEIRD_PASV_REPLY;
}
ftpc->newport = (unsigned short)num;
ftpc->newhost = control_address_dup(data, conn);
if(!ftpc->newhost)
return CURLE_OUT_OF_MEMORY;
result = ftp_control_addr_dup(data, ftpc);
if(result)
return result;
}
else
ptr = NULL;
@ -1884,7 +1893,9 @@ 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 = control_address_dup(data, conn);
result = ftp_control_addr_dup(data, ftpc);
if(result)
return result;
}
else
ftpc->newhost = curl_maprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
@ -1938,9 +1949,9 @@ 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 = control_address_dup(data, conn);
if(!ftpc->newhost)
return CURLE_OUT_OF_MEMORY;
result = ftp_control_addr_dup(data, ftpc);
if(result)
return result;
}
(void)Curl_resolv_blocking(data, ftpc->newhost, ftpc->newport,