通过 Python 的 ftplib 在防火墙后连接到 FTP 时控制正在使用的端口号

Controlling port numbers in use when connecting to FTP via Python's ftplib behind a firewall

我正在尝试从仅接受端口范围 6100–6200 的输出的防火墙后面连接到 FTP 服务器。我(相当天真,但基于对 the documentation 的阅读)正在尝试:

from ftplib import FTP

host_address="the.ftp.ip.address"
ftp = FTP()
ftp.connect(host=hostaddress, source_address=("127.0.0.1", 6100))

但这给出了错误:

In [42]: ftp = FTP(host_address, source_address=('127.0.0.1', 6100))
---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
<ipython-input-42-071ac06087bd> in <module>
----> 1 ftp = FTP(destination, source_address=('127.0.0.1', 6100))

~/SOFTWARE/anaconda3/envs/GDAL/lib/python3.9/ftplib.py in __init__(self, host, user, passwd, acct, timeout, source_address, encoding)
    117         self.timeout = timeout
    118         if host:
--> 119             self.connect(host)
    120             if user:
    121                 self.login(user, passwd, acct)

~/SOFTWARE/anaconda3/envs/GDAL/lib/python3.9/ftplib.py in connect(self, host, port, timeout, source_address)
    154             self.source_address = source_address
    155         sys.audit("ftplib.connect", self, self.host, self.port)
--> 156         self.sock = socket.create_connection((self.host, self.port), self.timeout,
    157                                              source_address=self.source_address)
    158         self.af = self.sock.family

~/SOFTWARE/anaconda3/envs/GDAL/lib/python3.9/socket.py in create_connection(address, timeout, source_address)
    841     if err is not None:
    842         try:
--> 843             raise err
    844         finally:
    845             # Break explicitly a reference cycle

~/SOFTWARE/anaconda3/envs/GDAL/lib/python3.9/socket.py in create_connection(address, timeout, source_address)
    829             if source_address:
    830                 sock.bind(source_address)
--> 831             sock.connect(sa)
    832             # Break explicitly a reference cycle
    833             err = None

OSError: [Errno 22] Invalid argument

在同一台机器上,我可以使用 curl:

成功列出文件
curl --ftp-port :6100-6200 --list-only $ftpserver

如何使用 ftplib 绕过本地防火墙连接到常规(即端口 21)FTP 服务器?

curl --ftp-port switch 启用 active 模式并设置本地 listening 端口用于 传入数据 个连接。

这不是您的代码所做的。您的代码使用 passive 模式并设置 source ports of outgoing control connection.


首先,如果您需要使用主动模式,这通常意味着您的 FTP 服务器或防火墙配置错误。主动模式实际上比被动模式需要更多的防火墙配置。你应该使用被动模式。这是一种工作量更少、功能更强大的解决方案。

请注意,在被动模式下,您无法控制使用的端口,因为那是服务器的决定,而不是客户端的。您必须配置本地防火墙(如果有)以允许服务器正在使用的数据连接端口。


如果确实需要使用主动模式,请使用FTP.set_pasv

ftp = FTP()
ftp.set_pasv(False)
ftp.connect(host=hostaddress)

ftplib 不允许您控制活动模式的端口。您必须在 ftplib FTP class 中编辑 makeport 方法或在您的代码中覆盖它。让它监听 sock.bind:

中的特定端口
  • How can I specify the client's data port for a ftp server in active mode?