How to make TidFTPServer working with SSL - delphi

I m looking for example but can't find one working. How can i make TidFTPServer accepting SSL connection (password and data encrypted) ? I understand that i need to use IdServerIOHandlerSSLOpenSSL but I can't make it working
This is the code i did :
fIdServerIOHandlerSSLOpenSSL := TIdServerIOHandlerSSLOpenSSL.Create(nil);
fIdServerIOHandlerSSLOpenSSL.SSLOptions.SSLVersions := [TIdSSLVersion.sslvSSLv2, TIdSSLVersion.sslvSSLv23, TIdSSLVersion.sslvSSLv3, TIdSSLVersion.sslvTLSv1, TIdSSLVersion.sslvTLSv1_1, TIdSSLVersion.sslvTLSv1_2];
fFTPServer.IOHandler := fIdServerIOHandlerSSLOpenSSL;
I have the error in the ftp server:
TIDFtpServer: Exception class EIdOSSLUnderlyingCryptoError with
message 'Error accepting connection with SSL. error:1408A0C1:SSL
routines:ssl3_get_client_hello:no shared cipher

Related

POST with Indy + SSL + Proxy

I'm trying to do a POST request through proxy using https.
Code looks like:
FHttp := TIdHttp.Create(nil);
FHttp.ProxyParams.ProxyServer := Host;
FHttp.ProxyParams.ProxyPort := Port;
FHttp.ProxyParams.ProxyUsername := User;
FHttp.ProxyParams.ProxyPassword := Password;
FHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
FHandler.SSLOptions.Method := sslvTLSv1_2;
FHandler.PassThrough := true;
FHttp.IOHandler := FHandler;
FHttp.HandleRedirects := true;
FHttp.Request.ContentType := 'application/x-www-form-urlencoded';
FHttp.Request.Connection := 'keep-alive';
FHttp.Request.ProxyConnection := 'keep-alive';
...
FParams.Add('username=user');
FParams.Add('password=pwd');
FHttp.Post('https://my.service/login', FParams);
Proxy server is Squid.
Code generates error "Socket Error # 10054 Connection reset by peer."
Now, the interesting part comes:
If not using proxy at all (i.e. not setting FHttp.ProxyParams settings) - everything is OK.
If not setting any POST parameters (i.e. empty FParams), but still using proxy - everything is OK.
The most strange one: If I'm debugging the Indy code step by step (TIdCustomHTTP.DoRequest method) - everything is OK with above example (proxy settings + parameters).
POST parameters are not sent properly for some reason?
And why step 3 is happening?
Indy is up to date, just pulled from repository
UPDATE
After intercepting TIdHTTP calls (thanks Remy) there is a little bit more clarity. (failing log, working log).
Short version: when doing debug, Indy does 3 CONNECT + POST + DISCONNECT requests (because there are redirection on the service I believe) and it works.
When running test without debug - CONNECT + DISCONNECT + POST - and it fails obviously (i.e. POST is executed without CONNECT in front).
See attached log files for details.
You have found some logic bugs in TIdHTTP that need to be fixed. I have opened a new ticket for that:
#315: Bugs in TIdHTTP proxy handling
Here is what I see happening in your "failing" scenario:
TIdHTTP connects to the proxy, sends a CONNECT request that successfully connects to my.service.com:443, then sends a POST request (using HTTP 1.0 rather than HTTP 1.1 a).
a) to send a POST request with HTTP 1.1, you have to set the TIdHTTP.ProtocolVersion property to pv1_1, AND enable the hoKeepOrigProtocol flag in the TIdHTTP.HTTPOptions property. Otherwise, TIdHTTP.Post() forces the ProtocolVersion to pv1_0.
The HTTP server replies with a 302 Found response redirecting to a different URL, including a Keep-Alive header indicating the server will close the connection if a new request is not sent in the next 5 seconds.
When TIdHTTP is done processing the POST response, it knows it is going to re-send the same request to a new URL. On the next loop iteration, it sees that the target server is the same, and the proxy is still connected, and so the connection is not closed, and the code that would have sent a new CONNECT request is skipped.
Just before the POST request is sent, the Response.KeepAlive property is checked to know whether or not to close the socket connection anyway. The KeepAlive property getter sees the ProtocolVersion property is pv1_0 and that there is no Proxy-Connection: keep-alive header present in the response (even though there is a Connection: keep-alive header), so it returns False, and then the socket connection is closed.
TIdHTTP then re-connects to the proxy again, but does not send a new CONNECT request before sending the POST request. The proxy does not know what to do with the POST, so it fails the request with a 400 Bad Request response.
Here is what I see happening in your "working" scenario:
Everything is the same as above, up to the point where the 1st POST request is processed. Then there is a delay of roughly 16 seconds (likely since you are stepping through code) - more than the 5-second Keep-Alive delay allows - so the HTTP server closes its connection with the proxy, which then closes its connection to TIdHTTP.
By the time TIdHTTP is ready to send the 2nd POST request, it knows it has been disconnected from the proxy, so it re-connects to the proxy, sends a new CONNECT request, and then sends the POST request.
Until I can fix the bugs properly, try the following:
enable the hoKeepOrigProtocol flag in the TIdHTTP.HTTPOptions property to allow TIdHTTP.Post() to use HTTP 1.1. That in itself may fix the issue with the connection being closed unnecessarily before sending the 2nd POST request to the redirected URL.
if that doesn't solve the issue, try editing IdHTTP.pas yourself and recompile Indy, to update the TIdCustomHTTP.ConnectToHost() method to force a Disconnect() if the Response.KeepAlive property is False BEFORE the local LUseConnectVerb variable is set to not Connected in the case where ARequest.UseProxy is ctSSLProxy (and ctProxy, too). That way, the 2nd POST request will disconnect from the proxy and re-connect with a new CONNECT request.

How to send mail using indy component in delphi xe2? [duplicate]

This question already has answers here:
Using Gmails Outgoing SMTP from DELPHI(Indy) using TLS
(3 answers)
SendEmail with Indy components
(2 answers)
Closed 9 years ago.
First i have this code and i tried with Gmail Smtp server but i have the result with error exception : Socket °10060 !!!!
it a delay socket error , please if any one tried this before and it work for him just share the idea with me thanks !!!!
VAR SMTP : TIdSMTP; VAR MSG : TIdMSG;
MSG:=TIdMSG.Create(NIL);
TRY
WITH MSG.Recipients.Add DO BEGIN
Name:='<Name of recipient>';
Address:='<Email address of recipient>'
END;
MSG.BccList.Add.Address:='<Email address of Blind Copy recipient>';
MSG.From.Name:='<Name of sender>';
MSG.From.Address:='<Email address of sender>';
MSG.Body.Text:='<Message Body>';
MSG.Subject:='<Subject of message>';
SMTP:=TIdSMTP.Create(NIL);
TRY
SMTP.Host:='x.x.x.x'; // IP Address of SMTP server
SMTP.Port:=25; // Port address of SMTP service (usually 25)
SMTP.Connect;
TRY
SMTP.Send(MSG)
FINALLY
SMTP.Disconnect
END
FINALLY
SMTP.Free
END
FINALLY
MSG.Free
END;

Why it returns 403 when TIdHTTPProxyServer tries to forward the request to most of proxy servers?

the question is extended from the question which I asked before.
Currently I can let my proxy server with TIdHTTPProxyServer forward the request to another proxy server which also using TIdHTTPProxyServer. But when I tried to let it forward the request to other proxy servers from the free proxy servers list on web. Most servers which can be used through IE proxy setting return 403 error message to my proxy server. In fact I have tried about 20 valid proxy servers, but only two can accept the requests from my proxy server. I can not figure out why it happens.
Below is the code I use in HTTPBeforeCommand of TIdHTTPProxyServer.
TIdIOHandlerStack* tempIO = new TIdIOHandlerStack(AContext->OutboundClient);
TIdConnectThroughHttpProxy* tempProxy = new TIdConnectThroughHttpProxy(AContext->OutboundClient);
tempProxy->Enabled = true;
tempProxy->Host = ProxyServerAddress;
tempProxy->Port = ProxyServerPort ;
tempIO->TransparentProxy = tempProxy;
AContext->OutboundClient->IOHandler = tempIO;
After monitoring the behaviors of TIdHTTPProxyServer using wireshark, I found TIdHTTPProxyServer always send a CONNECT request to other proxy servers at first berfore foward the real requests(the browser does not do that).
And then receive 403 response for most proxy servers. But still do not know how to make it works.
Updated on 2012/08/07
Hi, I am not really familiar with those HTTP stuffs, so I just record what I saw in wireshark here. It seems IE uses GET/POST commands for HTTP requests and CONNECT command for HTTPS requests. And most proxy servers block Connect commands when they are not HTTPS request (For example, CONNECT www.google.com.tw:80 HTTP/1.0). That is why TIdConnectThroughHttpProxy always does not work.
Below is my workaround, I made a little bit changes in IdHTTPProxyServer.pas. Hope it is useful for someone else who meets the same problems.
For CONNECT commands, still use TIdConnectThroughHttpProxy
Within TIdHTTPProxyServer.CommandCONNECT
if UseProxy = True then
begin
tempIO := TIdIOHandlerStack.Create(LContext.FOutboundClient);
tempProxy := TIdConnectThroughHttpProxy.Create(LContext.FOutboundClient);
tempProxy.Enabled := True;
tempProxy.Host := UseProxyAddr;
tempProxy.Port := UseProxyPort ;
tempIO.TransparentProxy := tempProxy;
LContext.FOutboundClient.IOHandler := tempIO;
end;
For GET/POST commands, I should directly send GET www.google.com.tw:80 HTTP/1.0 to other proxy servers instead of sending CONNECT www.google.com.tw:80 HTTP/1.0 at first.
Within TIdHTTPProxyServer.CommandPassThrough
if UseProxy = True then
begin
TIdTCPClient(LContext.FOutboundClient).Host := UseProxyAddr;
TIdTCPClient(LContext.FOutboundClient).Port := UseProxyPort;
end else
begin
TIdTCPClient(LContext.FOutboundClient).Host := LURI.Host;
TIdTCPClient(LContext.FOutboundClient).Port := IndyStrToInt(LURI.Port, 80);
end;
Also within TIdHTTPProxyServer.CommandPassThrough, I should let header Proxy-Connection = close
LContext.Connection.IOHandler.Capture(LContext.Headers, '', False);
LContext.Headers.Values['Proxy-Connection'] := 'close';
Finally within TIdHTTPProxyServer.TransferData
if AContext.TransferSource = tsClient then
begin
if UseProxy = True then
begin
ADest.IOHandler.WriteLn(AContext.Command + ' ' + AContext.Target + ' HTTP/1.0');
end else
begin
ADest.IOHandler.WriteLn(AContext.Command + ' ' + AContext.Document + ' HTTP/1.0');
end;
end;
It is my first time to implement delphi, and hope there are better solutions.
I believe you should not use pin-holing - http://www.indyproject.org/docsite/html/TIdConnectThroughHttpProxy.html
CONNECT command is not how WWW works. No browser use it. It is how non-WWW programs try to break-through the firewalls and open direct access to all areas of internet beyond WWW.
Don't use "transparent proxy" classes.
Use regular HTTP proxy, like in How to download a file over HTTPS using Indy 10 and OpenSSL?
BTW, there is no such event handler as u name "HTTPBeforeCommand"
http://www.indyproject.org/docsite/html/!!MEMBEROVERVIEW_TIdHTTPProxyServer.html

Get extended error information when an error 11004 occurs using TIdSmtp.Connect() method?

I have a Delphi 6 application that sends E-mails with attachments. When I first tested it I got an 11004 error (policy violation) when I called TIdSmtp.Connect(). It turned out my E-mail server SMTP setting were wrong and now it works fine. But know my users are going to run into trouble and I'd like to know if there is a way to get more extensive error information back from the SMTP server via the Indy components to help with my debugging efforts. I am using Indy 9 with Delphi 6.
Is there a way to get a much richer report and find out what the probable cause for the error is? (e.g. - SSL required, From field not filled in, rejected domain, etc). Also, same question but when an error occurs on the TIdSmtp.Send() method?
EIdSMTPReplyError is raised in response to an error message from the SMTP server at the SMTP protocol layer. 11004 is a socket/DNS error, not an SMTP error. There would be no additional error information available other than the basic OS error message (which you can get from SysErrorMessage()):
The requested name is valid and was found in the database, but it does not have the correct associated data being resolved for.
Regarding TIdSMTP.Send(), you can look for EIdSMTPReplyError exceptions, eg:
try
IdSMTP1.Connect;
try
IdSMTP1.Send(IdMessage1);
finally
IdSMTP1.Disconnect;
end;
except
on E: EIdSMTPReplyError do
Application.MessageBox(
PChar(
'Error message: ' + E.Message + sLineBreak +
'Error code: ' + IntToStr(E.ErrorCode) + sLineBreak +
'Error reply: ' + E.EnhancedCode.ReplyAsStr
),
'SMTP Error...', MB_OK + MB_ICONSTOP + MB_TOPMOST);
end;
That will help some, and if the server supports Extended Error Codes then you might get a little bit closer. But more times then not, you will not likely be able to distinquish EXACTLY what went wrong without looking at the actual SMTP command/response traffic over the wire.
Regarding SSL/TLS errors in particular, one of several different things may happen, depending on your TIdSMTP configuration:
1) you might get a general EIdSocketError exception raised, like with your 11004 error.
2) You might get an EIdSMTPReplyError exception with a malformed error code if you connect to a server port that requires Implicit SSL/TLS but you do not have TIdSMTP.UseTLS set to utUseImplicitTLS.
2) You might get an EIdOSSLConnectError or other OpenSSL-related exception if you have UseTLS=utUseImplicitTLS assigned but the server is not expecting Implicit SSL/TLS.
3) You have UseTLS set to either utUseExplicitTLS or utRequiresTLS and the server supports Explicit TLS, but the SSL/TLS handshake fails for whatever reason, you will get a TIdSMTP.OnTLSHandShakeFailed event triggered only for utUseExplicitTLS. If the event handler does not set VContinue=True, or you used utRequiresTLS, you will get an EIdTLSClientTLSHandShakeFailed exception raised.
4) You have UseTLS set to either utUseExplicitTLS or utRequiresTLS and the server does not support Explicit TLS, you will get a TIdSMTP.OnTLSNotAvailable event triggered for utUseExplicitTLS only. If the event handler does not set VContinue=True, or you used utRequiresTLS, you will then get an EIdTLSClientTLSNotAvailable exception raised.

Indy Mail server

Following is my code for the smtp client for sending email
VAR SMTP : TIdSMTP;
MSG : TIdmessage;
begin
MSG:=TIdmessage.Create(NIL);
TRY
WITH MSG.Recipients.Add DO BEGIN
Name:='me025';
Address:='me025#gmail.com'
END;
MSG.BccList.Add.Address:='me025#yahoo.com';
MSG.From.Name:='self025';
MSG.From.Address:='self025#127.0.1.1';
MSG.Body.Text:='<Message Body>';
MSG.Subject:='<Subject of message>';
SMTP:=TIdSMTP.Create(NIL);
TRY
SMTP.Host:='127.0.1.1'; // IP Address of SMTP server
// 127.0.1.1
SMTP.Port:=25; // Port address of SMTP service (usually 25)
SMTP.Connect;
TRY
SMTP.Send(MSG)
FINALLY
SMTP.Disconnect
END
FINALLY
SMTP.Free
END
FINALLY
MSG.Free
END;
end;
which will use a SMTPserver in same pc
the smtp server is a working indy 10 unofficial sample
http://indy.fulgan.com/ZIP/Indy10demo.zip
whenever i connect to the server "Socket error # 11001 Host not found " error occers
but smtp server is receiving all the parameters correctly and showing correctly on the GUI
Has your PC an address of 127.0.1.1 or are you trying to use localhost (127.0.0.1)? People should get used to DNS names... as soon as IPv6 will become mainstream at least people won't be able any longer to remember IP numbers easily :)

Resources