让FileZilla兼容FtpAnywhere
FileZilla FTP是一个著名的开源标准FTP客户端软件,但是它的目前版本与FtpAnywhere提供的网格FTP有兼容问题,而且,目前无法通过它提供的那些设置模块来实现兼容,因此,我特地下载了它的源代码快照 [2009.4.16] ,看看是否有可能通过修改源代码来让它兼容.
解压缩它的源代码,转到子目录\src\engine下,打开ftpcontrolsocket.cpp文件,这个文件就是FileZilla用来支持标准FTP指令的核心,需要改造的是它的列表模式以及对PASV反馈的分析代码 [包括IPV6下的EPSV指令,但是暂时因为没有IPV6,所以没必要动它],改造它的PASV解析代码
让FileZilla兼容FtpAnywhere
bool CFtpControlSocket::ParsePasvResponse(CRawTransferOpData* pData)
{
// Validate ip address
wxString digit = _T("0*[0-9]{1,3}");
const wxChar* dot = _T(",");
wxString exp = _T("( |\\()(") + digit + dot + digit + dot + digit + dot + digit + dot + digit + dot + digit + _T(")( |\\)|$)");
wxRegEx regex;
regex.Compile(exp);
if (!regex.Matches(m_Response))
return false;
pData->host = regex.GetMatch(m_Response, 2);
int i = pData->host.Find(',', true);
long number;
if (i == -1 || !pData->host.Mid(i + 1).ToLong(&number))
return false;
pData->port = number; //get ls byte of server socket
pData->host = pData->host.Left(i);
i = pData->host.Find(',', true);
if (i == -1 || !pData->host.Mid(i + 1).ToLong(&number))
return false;
pData->port += 256 * number; //add ms byte of server socket
pData->host = pData-> host.Left(i);
pData->host.Replace(_T(","), _T("."));
if (m_pProxyBackend)
{
// We do not have any information about the proxy's inner workings
return true;
}
const wxString peerIP = m_pSocket->GetPeerIP();
if (!IsRoutableAddress(pData->host, m_pSocket->GetAddressFamily()) && IsRoutableAddress(peerIP, m_pSocket->GetAddressFamily()))
{
if (!m_pEngine->GetOptions()->GetOptionVal(OPTION_PASVREPLYFALLBACKMODE) || pData->bTriedActive)
{
LogMessage(Status, _("Server sent passive reply with unroutable address. Using server address instead."));
LogMessage(Debug_Info, _T(" Reply: %s, peer: %s"), pData->host.c_str(), peerIP.c_str());
pData->host = peerIP;
}
else
{
LogMessage(Status, _("Server sent passive reply with unroutable address. Passive mode failed."));
LogMessage(Debug_Info, _T(" Reply: %s, peer: %s"), pData->host.c_str(), peerIP.c_str());
return false;
}
}
return true;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
这里是它原先的代码,导致PASV模式下无法下载的问题就出在它不知道有P2P传输这么个东西,因此加了个安全判断功能,只要把它注销就可以适合FtpAnywhere了,一般来说,只要FTP服务器是正规的服务器,那么这些代码完全是白费蜡,注销后的代码
让FileZilla兼容FtpAnywhere
bool CFtpControlSocket::ParsePasvResponse(CRawTransferOpData* pData)
{
// Validate ip address
wxString digit = _T("0*[0-9]{1,3}");
const wxChar* dot = _T(",");
wxString exp = _T("( |\\()(") + digit + dot + digit + dot + digit + dot + digit + dot + digit + dot + digit + _T(")( |\\)|$)");
wxRegEx regex;
regex.Compile(exp);
if (!regex.Matches(m_Response))
return false;
pData->host = regex.GetMatch(m_Response, 2);
int i = pData->host.Find(',', true);
long number;
if (i == -1 || !pData->host.Mid(i + 1).ToLong(&number))
return false;
pData->port = number; //get ls byte of server socket
pData->host = pData->host.Left(i);
i = pData->host.Find(',', true);
if (i == -1 || !pData->host.Mid(i + 1).ToLong(&number))
return false;
pData->port += 256 * number; //add ms byte of server socket
pData->host = pData-> host.Left(i);
pData->host.Replace(_T(","), _T("."));
if (m_pProxyBackend)
{
// We do not have any information about the proxy's inner workings
return true;
}
//注意,把下面的代码注销,就可以支持P2P PASV模式下的连接传输了
//const wxString peerIP = m_pSocket->GetPeerIP();
//if (!IsRoutableAddress(pData->host, m_pSocket->GetAddressFamily()) && IsRoutableAddress(peerIP, m_pSocket->GetAddressFamily()))
//{
//if (!m_pEngine->GetOptions()->GetOptionVal(OPTION_PASVREPLYFALLBACKMODE) || pData->bTriedActive)
//{
//LogMessage(Status, _("Server sent passive reply with unroutable address. Using server address instead."));
//LogMessage(Debug_Info, _T(" Reply: %s, peer: %s"), pData->host.c_str(), peerIP.c_str());
//pData->host = peerIP;
//}
//else
//{
//LogMessage(Status, _("Server sent passive reply with unroutable address. Passive mode failed."));
//LogMessage(Debug_Info, _T(" Reply: %s, peer: %s"), pData->host.c_str(), peerIP.c_str());
//return false;
//}
//}
return true;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
#p#
那么现在的代码,只要在站点属性的连接模式里,指定PORT为优先,在PORT模式连接失败后,设置自动切换到PASV模式,已经可以有条件兼容,只是***次下载会失败而已,下面我们改造它的列表模式,让它具备更好的兼容性. 当然,你可以在FtpAnywhere服务器里,设置禁止根目录下PASV列表,来让FileZilla自动判断连接模式,但是从它的代码看,它的判断还是存在一点兼容问题.因此,将LIST改造成主动模式优先,是***的选择.
问题在这里
CRawTransferOpData::CRawTransferOpData()
: COpData(cmd_rawtransfer)
{
bTriedPasv = bTriedActive = false;
bPasv = true;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
它的初始化是被动模式优先,这样,列表的时候将发生问题,但是下载可以成功,但是我阅读代码,发现除非额外指定一个列表时优先使用的模式变量,否则很难修改代码,因为它的代码中列表和文件传输的优先模式是一致的,还要适应其他标准FTP站点,毕竟我不可以能让它为我的FtpAnywhere进行优化,方法是,在FtpControlSocket.h里定义的类
class CRawTransferOpData : public COpData
{
public:
CRawTransferOpData();
wxString cmd;
CFtpTransferOpData* pOldData;
bool bPasv;
bool bTriedPasv;
bool bTriedActive;
wxString host;
int port;
};
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
给它加个额外的变量,例如 bool bFtpAnywhere;然后,在List指令前,确定首先采用PASV或者PORT前,判断 bFtpAnywhere是否为真,如果为真,那么列表应该优先采用PORT模式,否则继续执行默认的动作;而bFtpAnywhere的初始化应该从给服务器发送 VDSI指令是否返回2XX来判断,是否是一个FtpAnywhere服务器,因为这里涉及的修改太多,除非FileZilla代码维护人员同意,否则没有意义,因此,最简单最快的方法还是直接注销我上面给出的代码,虽然无法获得100%兼容,但是基本可以兼容,而且通过设置项目,可以做到手动兼容.
【编辑推荐】