embeddedmz / ftpclient-cpp

C++ client for making FTP requests
MIT License
211 stars 67 forks source link

How to use PassiveMode? #10

Open matteocostantini opened 4 years ago

embeddedmz commented 4 years ago

Hi Matteo,

It's possible to use the passive mode. I will give you an answer tonight.

Regards.

embeddedmz commented 4 years ago

@matteocostantini By default, the FTP client is in passive mode (m_bActive is initialized to false), so there's nothing to do.

To use the active mode use SetActive(true), in active mode, the client will choose a port and the FTP server will initialize the connection (not recommended if there's a firewall).

matteocostantini commented 4 years ago

This is my implementation, dont connect . i'm in UI environment.

How i can use?

My FTP credentials is valid ('m tryng with WINSCP!!)

in FTPCLient.cpp go in this rows else if (m_eSettingsFlags & ENABLE_LOG) m_oLog(StringFormat(LOG_ERROR_CURL_FILELIST_FORMAT, strRemoteFolder.c_str(), res, curl_easy_strerror(res)));

void BDImport::OnRunButton() { //m_pFTPClient = new CFTPClient(CFTPClient::LogFnCallback);

CFTPClient FTPClient([](const std::string& strLogMsg) { std::cout << strLogMsg << std::endl; });

CString host = _T("fqdnftp");
std::string stdHost = CT2CA(host);

CString user = _T("");
std::string stdUser = CT2CA(user);

CString pwd = _T("");
std::string stdpwd = CT2CA(pwd);

FTPClient.InitSession(stdHost, 6321, stdUser, stdpwd, CFTPClient::FTP_PROTOCOL::FTPES);

std::string strList;

FTPClient.List("/", strList, false);
embeddedmz commented 4 years ago

I never tested the FTP Client with this protocol CFTPClient::FTP_PROTOCOL::FTPES.

If you are trying to access a normal FTP server (port 21), remove that parameter (it will default to FTP_PROTOCOL::FTP) or set the protocol to FTP_PROTOCOL::SFTP if you want to connect to an SFTP server (port 22).

Also, in a debugger, check that the string parameters are well encoded (I don't know if CT2CA is doing its job properly). And that "stdHost" doesn't contain any protocol scheme.

embeddedmz commented 4 years ago

I'm not sure but to access secure servers, I think you need to set an SSL cert file with the static method SetSSLCertFile.

You can use this file : https://curl.haxx.se/ca/cacert.pem (from libcurl website)

and then CFTPClient::SetSSLCertFile("C:\\etc...............\\cacert.pem");

UPDATE : ignore this comment

embeddedmz commented 4 years ago

@matteocostantini You can also compile with this preprocessor macro DEBUG_CURL, and use this method : static void SetCurlTraceLogDirectory(const std::string &strPath); to specify a directory where debug logs will be stored. They will give you an information on why things are not working properly.

Also, don't forget to set a preprocessor macro WINDOWS as I believe you are not using the CMake scripts.

Regards.

matteocostantini commented 4 years ago

@embeddedmz : I'm able to connect to my server with this instructions:

curl_easy_setopt(m_pCurlSession, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(m_pCurlSession, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_easy_setopt(m_pCurlSession, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0);
curl_easy_setopt(m_pCurlSession, CURLOPT_FTP_SSL, CURLOPT_FTPSSLAUTH);
curl_easy_setopt(m_pCurlSession, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_TLS);

Can you improve this calls in your ::Perform()?

embeddedmz commented 4 years ago

First of all, to what kind of FTP servers are you connecting (SFTP, FTPES or FTPS). I know that the client work with SFTP but not the 2 others (FTPES, FTPS).

You can remove these 2 lines :

curl_easy_setopt(m_pCurlSession, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(m_pCurlSession, CURLOPT_SSL_VERIFYHOST, 0);

if you use this : curl_easy_setopt(m_pCurlSession, CURLOPT_CAINFO, "C:\....\cacert.pem");

In my previous comment I mistaken this for CFTPClient::SetSSLCertFile("C:\etc...............\cacert.pem"); it's missing in this client (but not in the httpclient-cpp). But your server must have a valid SSL certificate and not a quick & dirty one. Settings those 2 parameters to 0 is not good for all cases (security issues).

So, if you have the chance to add and test these getter/setters method :

// in .h static const std::string& GetCertificateFile() { return s_strCertificationAuthorityFile; } static void SetCertificateFile(const std::string& strPath) { s_strCertificationAuthorityFile = strPath; } //.... //SSL static std::string s_strCertificationAuthorityFile;

// in .cpp // just look to this https://github.com/embeddedmz/httpclient-cpp/blob/master/HTTP/HTTPClient.cpp and to the code that sets CURLOPT_CAINFO

In line 857 (if (m_eFtpProtocol == FTP_PROTOCOL::FTPS || m_eFtpProtocol == FTP_PROTOCOL::FTPES)) , you can add :

curl_easy_setopt(m_pCurlSession, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0);
curl_easy_setopt(m_pCurlSession, CURLOPT_FTP_SSL, CURLOPT_FTPSSLAUTH);
curl_easy_setopt(m_pCurlSession, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_TLS);

and eventually remove curl_easy_setopt(m_pCurlSession, CURLOPT_USE_SSL, CURLUSESSL_ALL); if it's not necessary

If everything is OK, create a pull request and I will merge your patches.

matteocostantini commented 4 years ago

the connection function successfully only if i put curl_easy_setopt(m_pCurlSession, CURLOPT_USE_SSL, CURLUSESSL_ALL); curl_easy_setopt(m_pCurlSession, CURLOPT_SSL_VERIFYPEER, FALSE); curl_easy_setopt(m_pCurlSession, CURLOPT_SSL_VERIFYHOST, FALSE); curl_easy_setopt(m_pCurlSession, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0); curl_easy_setopt(m_pCurlSession, CURLOPT_FTP_SSL, CURLOPT_FTPSSLAUTH); curl_easy_setopt(m_pCurlSession, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_TLS);

matteocostantini commented 4 years ago

The server is ftp with explicit autentication

embeddedmz commented 4 years ago

@matteocostantini OK, I googled curl FTPS/FTPES and I found the following stuff :

https://stackoverflow.com/questions/32491790/php-curl-ftpes-w-explicit-tls-ssl => in the code, instead of prefixing the URL with ftps:// prefix it with ftp:// that should be sufficient.

https://curl.haxx.se/docs/manual.html (curl doc.) => FTPS : It is just like for FTP, but you may also want to specify and use SSL-specific options for certificates etc. Note that using FTPS:// as prefix is the "implicit" way as described in the standards while the recommended "explicit" way is done by using FTP:// and the --ftp-ssl option.

So, can you please try this fix and tell me if the example you posted in the beginning of this thread is working : In line 194, add "case FTP_PROTOCOL::FTPES:" so that in a FTPES session, the url will be prefixed with ftp:// and remove the case of lines 203 and 205 (old code prefixing the url with ftpes://)

That should work fine (I hope so).