ftp: retry getpeername for FTP with TCP_FASTOPEN

In the case of TFO, the remote host name is not resolved at the
connetion time.

For FTP that has lead to missing hostname for the secondary connection.
Therefore the name resolution is done at the time, when FTP requires it.

Fixes #6252
Closes #6265
Closes #6282
This commit is contained in:
Klaus Crusius 2020-11-28 18:17:11 +01:00 committed by Daniel Stenberg
parent 7a6fdd503d
commit 2c0d721215
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
3 changed files with 71 additions and 46 deletions

View File

@ -671,59 +671,71 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
return FALSE;
}
/* retrieves the start/end point information of a socket of an established
connection */
void Curl_conninfo_remote(struct connectdata *conn, curl_socket_t sockfd)
{
#ifdef HAVE_GETPEERNAME
char buffer[STRERROR_LEN];
struct Curl_sockaddr_storage ssrem;
curl_socklen_t plen;
plen = sizeof(struct Curl_sockaddr_storage);
if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) {
int error = SOCKERRNO;
failf(conn->data, "getpeername() failed with errno %d: %s",
error, Curl_strerror(error, buffer, sizeof(buffer)));
return;
}
if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
conn->primary_ip, &conn->primary_port)) {
failf(conn->data, "ssrem inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
}
memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
#else
(void)conn;
(void)sockfd;
#endif
}
/* retrieves the start/end point information of a socket of an established
connection */
void Curl_conninfo_local(struct connectdata *conn, curl_socket_t sockfd)
{
#ifdef HAVE_GETSOCKNAME
char buffer[STRERROR_LEN];
struct Curl_sockaddr_storage ssloc;
curl_socklen_t slen;
slen = sizeof(struct Curl_sockaddr_storage);
memset(&ssloc, 0, sizeof(ssloc));
if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) {
int error = SOCKERRNO;
failf(conn->data, "getsockname() failed with errno %d: %s",
error, Curl_strerror(error, buffer, sizeof(buffer)));
return;
}
if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
conn->local_ip, &conn->local_port)) {
failf(conn->data, "ssloc inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
}
#else
(void)conn;
(void)sockfd;
#endif
}
/* retrieves the start/end point information of a socket of an established
connection */
void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
{
if(conn->transport == TRNSPRT_TCP) {
#if defined(HAVE_GETPEERNAME) || defined(HAVE_GETSOCKNAME)
if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
struct Curl_easy *data = conn->data;
char buffer[STRERROR_LEN];
struct Curl_sockaddr_storage ssrem;
struct Curl_sockaddr_storage ssloc;
curl_socklen_t plen;
curl_socklen_t slen;
#ifdef HAVE_GETPEERNAME
plen = sizeof(struct Curl_sockaddr_storage);
if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) {
int error = SOCKERRNO;
failf(data, "getpeername() failed with errno %d: %s",
error, Curl_strerror(error, buffer, sizeof(buffer)));
return;
}
#endif
#ifdef HAVE_GETSOCKNAME
slen = sizeof(struct Curl_sockaddr_storage);
memset(&ssloc, 0, sizeof(ssloc));
if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) {
int error = SOCKERRNO;
failf(data, "getsockname() failed with errno %d: %s",
error, Curl_strerror(error, buffer, sizeof(buffer)));
return;
}
#endif
#ifdef HAVE_GETPEERNAME
if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
conn->primary_ip, &conn->primary_port)) {
failf(data, "ssrem inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
}
memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
#endif
#ifdef HAVE_GETSOCKNAME
if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
conn->local_ip, &conn->local_port)) {
failf(data, "ssloc inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
}
#endif
Curl_conninfo_remote(conn, sockfd);
Curl_conninfo_local(conn, sockfd);
}
#else /* !HAVE_GETSOCKNAME && !HAVE_GETPEERNAME */
(void)sockfd; /* unused */
#endif
} /* end of TCP-only section */
/* persist connection info in session handle */

View File

@ -75,6 +75,8 @@ void Curl_sndbufset(curl_socket_t sockfd);
#endif
void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd);
void Curl_conninfo_remote(struct connectdata *conn, curl_socket_t sockfd);
void Curl_conninfo_local(struct connectdata *conn, curl_socket_t sockfd);
void Curl_persistconninfo(struct connectdata *conn);
int Curl_closesocket(struct connectdata *conn, curl_socket_t sock);

View File

@ -1940,6 +1940,17 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
#endif
{
/* normal, direct, ftp connection */
DEBUGASSERT(ftpc->newhost);
/* postponed address resolution in case of tcp fastopen */
if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) {
Curl_conninfo_remote(conn, conn->sock[FIRSTSOCKET]);
Curl_safefree(ftpc->newhost);
ftpc->newhost = strdup(control_address(conn));
if(!ftpc->newhost)
return CURLE_OUT_OF_MEMORY;
}
rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, FALSE, &addr);
if(rc == CURLRESOLV_PENDING)
/* BLOCKING */