Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FTP connection reuse not working in libcurl 8.12.1 #16384

Closed
Zenju opened this issue Feb 18, 2025 · 14 comments
Closed

FTP connection reuse not working in libcurl 8.12.1 #16384

Zenju opened this issue Feb 18, 2025 · 14 comments

Comments

@Zenju
Copy link
Contributor

Zenju commented Feb 18, 2025

I did this

  1. Standard TLS-encypted connection to Apache FTP server.

  2. Multiple FTP accesses using ::curl_easy_reset() on the same curl easy handle

=> TLS-enabled FTP control connection is not reused, see Wireshark log:
Image

Analysis so far:

Problem is caused by:

  if((!(needle->handler->flags&PROTOPT_SSL) !=
      !Curl_conn_is_ssl(conn, FIRSTSOCKET)) &&
     !(get_protocol_family(conn->handler) == needle->handler->protocol &&
       conn->bits.tls_upgraded))
    /* Deny `conn` if it is not fit for `needle`'s SSL needs,
     * UNLESS `conn` is the same protocol family and was upgraded to SSL. */
      return FALSE;

https://github.com/icing/curl/blob/3be33a1a4777438e2ef9cca488322f789bdd40fd/lib/url.c#L955

In libcurl 8.11.1 this line was

  if ((needle->handler->flags&PROTOPT_SSL) !=
        (conn->handler->flags&PROTOPT_SSL))
        /* do not do mixed SSL and non-SSL connections */
        if (get_protocol_family(conn->handler) !=
            needle->handler->protocol || !conn->bits.tls_upgraded)
            /* except protocols that have been upgraded via TLS */
            return FALSE;

In the 8.12.1 code
Curl_conn_is_ssl(conn, FIRSTSOCKET) returns "true",

while in 8.11.1
(conn->handler->flags&PROTOPT_SSL) evaluated to "false".

Reverting this code section back to 8.11.1 fixed FTP connection reuse in my tests.

I expected the following

FTP control connection should be reused instead of needlessly creating a new one each time

curl/libcurl version

8.12.1

operating system

Windows 10

@Zenju
Copy link
Contributor Author

Zenju commented Feb 18, 2025

Related: #16034

@bagder
Copy link
Member

bagder commented Feb 19, 2025

Multiple FTP accesses using ::curl_easy_reset() on the same curl easy handle

Does it work correctly without the reset done?

@Zenju
Copy link
Contributor Author

Zenju commented Feb 19, 2025

Does it work correctly without the reset done?

I don't understand the question. How would you make multiple FTP accesses without using curl_easy_reset(), while reusing the same connection?

@bagder
Copy link
Member

bagder commented Feb 19, 2025

Just use the same handle again?

@Zenju
Copy link
Contributor Author

Zenju commented Feb 19, 2025

The program crashes in ftp.c ftp_state_quote.

curl_easy_reset() is required for my use case as the FTP accesses vary a lot: file/folder creates, updates, deletes, folder traversal, lots of CURLOPT_CUSTOMREQUEST. On the other hand, not having connection reuse in libcurl is a showstopper bug.

@bagder
Copy link
Member

bagder commented Feb 19, 2025

The program crashes in ftp.c ftp_state_quote.

crashes ? That sounds like a separate bug then. Or you took away the list from under libcurl's feet.

@Zenju
Copy link
Contributor Author

Zenju commented Feb 19, 2025

I have no idea. Just commenting out "curl_easy_reset" quick and dirty. The libcurl access pattern in my software FreeFileSync is complex.

@icing icing self-assigned this Feb 19, 2025
icing added a commit to icing/curl that referenced this issue Feb 19, 2025
In curl 8.12 I tried to improve the logic on how we handle connections
that "upgrade" to TLS later, e.g. with a STARTTLS. I found the existing
code hard to read in this regard. But of course, the "improvements"
blew up in my face.

We fixed issues with imap, opo3, smtp in 8.12.1, but ftp was no longer
reusing existing, upgraded control connections as before. This PR adds
checks in our pytest FTP tests that verify reuse is happening as intended.

I rewrote the logic in url.c again, so that the new test checks now pass.

refs curl#16384
@icing
Copy link
Contributor

icing commented Feb 19, 2025

Thanks for the report. You pointed exactly at the location that was the problem.

I added checks in out test suite, reproducing the problem, and rewrote the logic in url.c again in #16392.

It would be great if you could verify that this solves your problem. Thanks.

@Zenju
Copy link
Contributor Author

Zenju commented Feb 19, 2025

I added checks in out test suite, reproducing the problem, and rewrote the logic in url.c again in #16392.

It would be great if you could verify that this solves your problem. Thanks.

Yes, this works! The TLS-enabled control connection is being reused as expected!

@Zenju
Copy link
Contributor Author

Zenju commented Feb 19, 2025

I'm wondering: Is FTP "AUTH TLS" considered an TLS-upgraded connection?

If "yes", then adding

        conn->bits.tls_upgraded = true;

after

        result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
                               ftpauth[ftpc->count1]);
        if(!result)
          ftp_state(data, FTP_AUTH);

https://github.com/curl/curl/blob/2335cbaa217af072b58b87911191acac8dbc7092/lib/ftp.c#L2727C1-L2727C2

would also fix the caching bug.

@icing
Copy link
Contributor

icing commented Feb 19, 2025

I am not aware of what the "caching bug" is, but I am on a mission to eliminate bits.tls_upgraded completely. It had been the only way to track if the connection speaks SSL, but we now have a better way of checking that, namely if an SSL filter is in place at the connection or not.

The only place left where bits.tls_upgraded is being evaluated is url.c line 1101 and that looks very close to the check we are currently fixing. Hmm...

@Zenju
Copy link
Contributor Author

Zenju commented Feb 19, 2025

I am not aware of what the "caching bug" is,

I mean what this ticket is about.

but I am on a mission to eliminate bits.tls_upgraded complete.

Ok, cool. Either way this showstopper bug is fixed for me. So thanks a lot!

@icing
Copy link
Contributor

icing commented Feb 19, 2025

I am not aware of what the "caching bug" is,

I mean what this ticket is about.

but I am on a mission to eliminate bits.tls_upgraded complete.

Ok, cool. Either way this showstopper bug is fixed for me. So thanks a lot!

Just pushed to #16392 and the bits.tls_upgraded is gone. Added tests with ftps: urls. If you could throw that one in your grinder, would appreciate it.

@Zenju
Copy link
Contributor Author

Zenju commented Feb 19, 2025

Just pushed to #16392 and the bits.tls_upgraded is gone. Added tests with ftps: urls. If you could throw that one in your grinder, would appreciate it.

Looking good! Works correctly with connection channel caching while traversing a large folder via FTP both with and without TLS enabled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

3 participants