Question

Is there a way to detect that the server returns its private network address when entering passive mode, and to translate it into its public address?
I don't have access to the server.

>>> # Python 2.7.3rc2
>>> from ftplib import FTP_TLS
>>> ftps = FTP_TLS()
>>> ftps.set_debuglevel(2)
>>> ftps.connect("example.com", 123)
*get* '220 Welcome to Synchrony Gateway FTP server\r\n'
*resp* '220 Welcome to Synchrony Gateway FTP server'
'220 Welcome to Synchrony Gateway FTP server'

>>> ftps.auth()
*cmd* 'AUTH TLS'
*put* 'AUTH TLS\r\n'
*get* '234 Using authentication type TLS\r\n'
*resp* '234 Using authentication type TLS'
'234 Using authentication type TLS'

>>> ftps.login("foo", "***")
*cmd* 'AUTH TLS'
*put* 'AUTH TLS\r\n'
*get* '234 AUTH command OK, waiting handshake\r\n'
*resp* '234 AUTH command OK, waiting handshake'
*cmd* 'USER foo'
*put* 'USER foo\r\n'
*get* '331 Send password please\r\n'
*resp* '331 Send password please'
*cmd* 'PASS ************'
*put* 'PASS ************\r\n'
*get* '230 User logged in, proceed\r\n'
*resp* '230 User logged in, proceed'
'230 User logged in, proceed'

>>> ftps.prot_p()
*cmd* 'PBSZ 0'
*put* 'PBSZ 0\r\n'
*get* '200 Command okay\r\n'
*resp* '200 Command okay'
*cmd* 'PROT P'
*put* 'PROT P\r\n'
*get* '200 Command okay\r\n'
*resp* '200 Command okay'
'200 Command okay'

>>> ftps.set_pasv(True)
>>> ftps.retrlines("LIST")
*cmd* 'TYPE A'
*put* 'TYPE A\r\n'
*get* '200 Type set to A\r\n'
*resp* '200 Type set to A'
*cmd* 'PASV'
*put* 'PASV\r\n'
*get* '227 Entering Passive Mode (192,168,17,1,195,119)\r\n'
*resp* '227 Entering Passive Mode (192,168,17,1,195,119)'

Thanks.

Was it helpful?

Solution

Configure the server to enter passive mode on an external IP.

OTHER TIPS

I ran into a similar problem. Here's a quick way to overwrite the local ip returned by the remote host:

from ftplib import FTP, parse227, parse229
import socket
class MyFTP(FTP):
    def makepasv(self):
        if self.af == socket.AF_INET:
            host, port = parse227(self.sendcmd('PASV'))
        else:
            host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
        # We tweak this so we don't use the internal ip returned by the remote server.
        # old: `return host, port`
        return self.host, port

Note that you can't use super(), because FTP is an 'old style' python class.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top