Python FTPS 在被动模式下挂在目录列表上
Python FTPS hangs on directory list in passive mode
我设法使用 curl 连接到 FTP 服务器并列出了目录 out
:
的内容
$ curl -v --insecure --ftp-ssl --user xxx:yyy blabla:990/out/
> AUTH SSL
< 234 Proceed with negotiation.
...
> USER xxx
< 331 Please specify the password.
> PASS yyy
< 230 Login successful.
> PBSZ 0
< 200 PBSZ set to 0.
> PROT P
< 200 PROT now Private.
> PWD
< 257 "/"
> CWD out
< 250 Directory successfully changed.
> EPSV
< 229 Entering Extended Passive Mode (|||51042|).
* Trying aaa.bbb.ccc.ddd...
* Connecting to aaa.bbb.ccc.ddd (aaa.bbb.ccc.ddd) port 51042
* Connected to blabla (aaa.bbb.ccc.ddd) port 990 (#0)
> TYPE A
< 200 Switching to ASCII mode.
> LIST
< 150 Here comes the directory listing.
* Maxdownload = -1
* Doing the SSL/TLS handshake on the data stream
* SSL re-using session ID
* TLS 1.0 connection using TLS_RSA_WITH_AES_256_CBC_SHA
* Server certificate: blabla
* Server certificate: Symantec Class 3 Secure Server CA - G4
* Server certificate: VeriSign Class 3 Public Primary Certification Authority - G5
{ [539 bytes data]
100 539 0 539 0 0 900 0 --:--:-- --:--:-- --:--:-- 899* Remembering we are in dir "out/"
< 226 Directory send OK.
我尝试使用 python(2.7.10 on Mac OS X 10.10.5)
import ftplib
ftps = ftplib.FTP_TLS()
ftps.set_debuglevel(1)
print ftps.set_pasv(True)
print ftps.connect("blabla", 990)
print ftps.login("xxx", "yyy")
print ftps.sendcmd("PBSZ 0")
print ftps.prot_p()
print ftps.pwd()
print ftps.cwd("out")
print ftps.transfercmd("LIST")
ftps.close()
但是 python LIST command
无限期挂起
*cmd* 'AUTH TLS'
*resp* '234 Proceed with negotiation.'
*cmd* 'USER xxx'
*resp* '331 Please specify the password.'
*cmd* 'PASS ********\n'
*resp* '230 Login successful.'
230 Login successful.
*cmd* 'PBSZ 0'
*resp* '200 PBSZ set to 0.'
200 PBSZ set to 0.
*cmd* 'PBSZ 0'
*resp* '200 PBSZ set to 0.'
*cmd* 'PROT P'
*resp* '200 PROT now Private.'
200 PROT now Private.
*cmd* 'PWD'
*resp* '257 "/"'
/
*cmd* 'CWD out'
*resp* '250 Directory successfully changed.'
250 Directory successfully changed.
*cmd* 'PASV'
*resp* '227 Entering Passive Mode (aa,bb,cc,dd,199,97).'
为什么会这样?
更新:好的,我在我的 curl 命令中添加了选项 --disable-epsv
,但也失败了。所以 python 无法列出目录的原因是使用了 PASV
。我如何强制 Python 改用 EPSV
?
更新 2:当 PASV 返回的 IP 地址错误时,这个错误 https://github.com/python/cpython/pull/28 似乎会导致 Python ftplib 挂起。这似乎也是我的问题。但是有人知道如何强制 Python 改用 EPSV
的解决方法吗?
通过阅读 ftplib 的源代码,我认为可以通过设置
强制 ftplib 使用 EPSV
ftps.af = socket.AF_INET6
这使得 ftplib 认为我们正在使用 IPv6 连接(即使我们实际上正在使用 IPv4)并使其使用 EPSV
而不是 PASV
。我的完整工作程序在最后
import ftplib
import socket
ftps = ftplib.FTP_TLS()
ftps.connect("blabla", 990)
ftps.login("xxx", "yyy")
ftps.prot_p()
ftps.cwd("out")
ftps.af = socket.AF_INET6
ftps.retrlines("LIST")
ftps.quit()
我设法使用 curl 连接到 FTP 服务器并列出了目录 out
:
$ curl -v --insecure --ftp-ssl --user xxx:yyy blabla:990/out/
> AUTH SSL
< 234 Proceed with negotiation.
...
> USER xxx
< 331 Please specify the password.
> PASS yyy
< 230 Login successful.
> PBSZ 0
< 200 PBSZ set to 0.
> PROT P
< 200 PROT now Private.
> PWD
< 257 "/"
> CWD out
< 250 Directory successfully changed.
> EPSV
< 229 Entering Extended Passive Mode (|||51042|).
* Trying aaa.bbb.ccc.ddd...
* Connecting to aaa.bbb.ccc.ddd (aaa.bbb.ccc.ddd) port 51042
* Connected to blabla (aaa.bbb.ccc.ddd) port 990 (#0)
> TYPE A
< 200 Switching to ASCII mode.
> LIST
< 150 Here comes the directory listing.
* Maxdownload = -1
* Doing the SSL/TLS handshake on the data stream
* SSL re-using session ID
* TLS 1.0 connection using TLS_RSA_WITH_AES_256_CBC_SHA
* Server certificate: blabla
* Server certificate: Symantec Class 3 Secure Server CA - G4
* Server certificate: VeriSign Class 3 Public Primary Certification Authority - G5
{ [539 bytes data]
100 539 0 539 0 0 900 0 --:--:-- --:--:-- --:--:-- 899* Remembering we are in dir "out/"
< 226 Directory send OK.
我尝试使用 python(2.7.10 on Mac OS X 10.10.5)
import ftplib
ftps = ftplib.FTP_TLS()
ftps.set_debuglevel(1)
print ftps.set_pasv(True)
print ftps.connect("blabla", 990)
print ftps.login("xxx", "yyy")
print ftps.sendcmd("PBSZ 0")
print ftps.prot_p()
print ftps.pwd()
print ftps.cwd("out")
print ftps.transfercmd("LIST")
ftps.close()
但是 python LIST command
无限期挂起
*cmd* 'AUTH TLS'
*resp* '234 Proceed with negotiation.'
*cmd* 'USER xxx'
*resp* '331 Please specify the password.'
*cmd* 'PASS ********\n'
*resp* '230 Login successful.'
230 Login successful.
*cmd* 'PBSZ 0'
*resp* '200 PBSZ set to 0.'
200 PBSZ set to 0.
*cmd* 'PBSZ 0'
*resp* '200 PBSZ set to 0.'
*cmd* 'PROT P'
*resp* '200 PROT now Private.'
200 PROT now Private.
*cmd* 'PWD'
*resp* '257 "/"'
/
*cmd* 'CWD out'
*resp* '250 Directory successfully changed.'
250 Directory successfully changed.
*cmd* 'PASV'
*resp* '227 Entering Passive Mode (aa,bb,cc,dd,199,97).'
为什么会这样?
更新:好的,我在我的 curl 命令中添加了选项 --disable-epsv
,但也失败了。所以 python 无法列出目录的原因是使用了 PASV
。我如何强制 Python 改用 EPSV
?
更新 2:当 PASV 返回的 IP 地址错误时,这个错误 https://github.com/python/cpython/pull/28 似乎会导致 Python ftplib 挂起。这似乎也是我的问题。但是有人知道如何强制 Python 改用 EPSV
的解决方法吗?
通过阅读 ftplib 的源代码,我认为可以通过设置
强制 ftplib 使用EPSV
ftps.af = socket.AF_INET6
这使得 ftplib 认为我们正在使用 IPv6 连接(即使我们实际上正在使用 IPv4)并使其使用 EPSV
而不是 PASV
。我的完整工作程序在最后
import ftplib
import socket
ftps = ftplib.FTP_TLS()
ftps.connect("blabla", 990)
ftps.login("xxx", "yyy")
ftps.prot_p()
ftps.cwd("out")
ftps.af = socket.AF_INET6
ftps.retrlines("LIST")
ftps.quit()