gh-127478: ftplib: prefer EPSV over PASV on IPv4 connections#150236
Open
simonepelosi wants to merge 3 commits into
Open
gh-127478: ftplib: prefer EPSV over PASV on IPv4 connections#150236simonepelosi wants to merge 3 commits into
simonepelosi wants to merge 3 commits into
Conversation
makepasv() now tries EPSV (RFC 2428) before PASV when connected over IPv4. EPSV returns only a port number without an IP address, making it transparent to firewall FTP Application Layer Gateways (ALGs) that intercept and often mangle PASV responses containing embedded IPs. Falls back to PASV if the server responds with an error to EPSV. A new class attribute FTP.prefer_epsv (default True) allows reverting to the old PASV-first behavior when set to False. This also fixes connectivity issues caused by the trust_server_pasv_ipv4_address security fix (bpo-43285): when firewalls rewrite PASV responses, clients connecting to the control channel IP on the data port often fail because nothing is listening there. EPSV avoids this entirely since the client always connects back to the same IP.
Documentation build overview
5 files changed ·
|
Replace :meth:`makepasv` references (undocumented method) with plain prose to avoid unresolved cross-reference warnings in nitpicky mode.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ftplib.FTP.makepasv()now prefers EPSV (RFC 2428) over PASV when connected over IPv4, with automatic fallback to PASV if the server does not support EPSV.Motivation
PASV responses embed an IP address (
227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)), which causes two classes of problems:Firewall FTP ALG interference: Next-Generation Firewalls with FTP Application Layer Gateways intercept PASV responses to parse/rewrite the embedded IP and set up data channel "pinholes". These ALGs frequently mangle or drop the response, causing
550 internal server erroror connection timeouts.Interaction with bpo-43285 security fix: Since Python 3.9.3,
trust_server_pasv_ipv4_addressdefaults toFalse, causing ftplib to ignore the PASV IP and connect the data channel to the control connection IP. When infrastructure uses load balancers or content caches in front of FTP servers, the control connection IP often has no listener on passive data ports, resulting in timeouts.EPSV (
229 Entering Extended Passive Mode (|||port|)) returns only a port number — no IP address. This makes it:EPSV has been an RFC standard since 1998 (27 years) and is universally supported by FTP servers. ftplib already uses EPSV unconditionally on IPv6 — this change extends that preference to IPv4.
Changes
Lib/ftplib.py: AddedFTP.prefer_epsv = Trueclass attribute.makepasv()tries EPSV first on IPv4, falls back to PASV onerror_perm.Lib/test/test_ftplib.py:cmd_epsvhandler to useself.socket.familyinstead of hardcodedAF_INET6(enables EPSV testing on IPv4)test_makepasv_prefer_epsv_disabled— verifies PASV is used whenprefer_epsv=Falsetest_makepasv_prefer_epsv_fallback_to_pasv— verifies graceful fallback when server rejects EPSVprefer_epsv=False(they test PASV-specific behavior)Misc/NEWS.d: Changelog entryBackwards Compatibility
ftp.prefer_epsv = Falseto restore the old PASV-first behavior.trust_server_pasv_ipv4_addresshandling).Testing
ppa.launchpad.net) where PASV fails through firewall ALG but EPSV succeedsReal-World Impact
This fixes FTP uploads for all Python FTP clients connecting through firewalls with FTP ALG enabled — a common enterprise and ISP configuration.
Closes #127478