diff -r 0bf8c07e1072 Lib/ftplib.py --- a/Lib/ftplib.py Sun Oct 18 23:12:37 2009 +0200 +++ b/Lib/ftplib.py Sun Oct 18 23:55:30 2009 +0200 @@ -104,6 +104,7 @@ class FTP: file = None welcome = None passiveserver = 1 + passive_ignore_host = False # Initialization method (called by class instantiation). # Initialize host to localhost, port to standard ftp port @@ -150,11 +151,16 @@ class FTP: self.debugging = level debug = set_debuglevel - def set_pasv(self, val): + def set_pasv(self, val, ignore_host=False): '''Use passive or active mode for data transfers. With a false argument, use the normal PORT mode, - With a true argument, use the PASV command.''' + With a true argument, use the PASV command. + + If `ignore_host` is True, the host address returned as part of + the PASV response by the server will be ignored. This is to work + with servers which return a bogus (e.g. private) address.''' self.passiveserver = val + self.passive_ignore_host = ignore_host # Internal: "sanitize" a string for printing def sanitize(self, s): @@ -301,6 +307,8 @@ class FTP: host, port = parse227(self.sendcmd('PASV')) else: host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername()) + if self.passive_ignore_host: + host = self.host return host, port def ntransfercmd(self, cmd, rest=None): diff -r 0bf8c07e1072 Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py Sun Oct 18 23:12:37 2009 +0200 +++ b/Lib/test/test_ftplib.py Sun Oct 18 23:55:30 2009 +0200 @@ -37,6 +37,8 @@ class DummyDTPHandler(asynchat.async_cha class DummyFTPHandler(asynchat.async_chat): + # If non-False, returns a bogus (unroutable) IP as part of a PASV response. + bogus_pasv_host = False def __init__(self, conn): asynchat.async_chat.__init__(self, conn) @@ -90,6 +92,8 @@ class DummyFTPHandler(asynchat.async_cha sock.listen(5) sock.settimeout(2) ip, port = sock.getsockname()[:2] + if self.bogus_pasv_host: + ip = self.bogus_pasv_host ip = ip.replace('.', ','); p1 = port / 256; p2 = port % 256 self.push('227 entering passive mode (%s,%d,%d)' %(ip, p1, p2)) conn, addr = sock.accept() @@ -361,6 +365,15 @@ class TestFTPClass(TestCase): # IPv4 is in use, just make sure send_epsv has not been used self.assertEqual(self.server.handler.last_received_cmd, 'pasv') + def test_bogus_pasv(self): + self.server.handler.bogus_pasv_host = '255.255.255.255' + try: + self.client.set_pasv(True, ignore_host=True) + received = [] + self.client.retrbinary('retr', received.append) + self.assertEqual(''.join(received), RETR_DATA) + finally: + self.server.handler.bogus_pasv_host = False class TestIPv6Environment(TestCase):