Python FTPS以被动模式

时间:2016-02-23 15:24:19

标签: python curl ftp ftplib

我设法使用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(Mac OS X 10.10.5上的2.7.10)

进行相同的操作
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代替?

UPDATE2:当PASV返回的IP地址错误时,此错误https://github.com/python/cpython/pull/28似乎导致Python ftplib挂起。这似乎也是我的问题。但有没有人知道如何强制Python使用EPSV代替?

1 个答案:

答案 0 :(得分:3)

通过阅读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()