Which transport protocol does IdHTTP use - delphi

I have been asked by a company to document that our client only communicates to our server over the TCP protocol on a software level. I have always assumed that IdHTTP utilizes TCP but I am not sure how to prove it. I have not been able to find it in the documentation.

TIdHTTP is ultimately derived from TIdTCPConnection, so it uses TCP by default 1.
1. Though this can be changed by assigning a non-TCP based TIdIOHandler-derived component to the TIdHTTP.IOHandler property.

Related

Are there SSL behaviour changes in Delphi 11?

For months, I have used the IdWebSocketSimpleClient unit with Delphi 10.3 provided here to setup a Websocket connection to the discord gateway API. Now, that I changed to Delphi 11, the same code shows another behaviour.
Previously, the component connected to the server, initiated an HTTP Upgrade to a websocket connection, received the 101 - switching protocols response and started to communicate. Now, with Delphi 11, I receive a 400 - Bad request. The inner error message shows "The plain HTTP request was sent to HTTPS port". In both scenarios, the same OpenSSL dll files are sitting in the applications executable folder and an TIdSSLIOHandlerSocketOpenSSL component is used.
At this point, I am really confused why this is happening, as the programs code hasn't been changed. This makes me wonder if there have been any behaviour changes to the indy units involved. I have no clue where to even start my investigation. Can someone help?
Delphi 10.3 was released in late 2018. There was a change made to the TIdSSLIOHandlerSocketBase class in late 2019, to fix a bug where its PassThrough property was being initialized to False when it should have been initialized to True instead (which is now the current behavior).
So, that could easily account for the behavior you are seeing, as the error message is complaining about an unsecured HTTP message being sent to a secure HTTPS port (because PassThrough is likely True).
That change did not affect most Indy components, as internally they explicitly set PassThrough as needed (typically based on a UseTLS property, or a specific URL protocol/port being requested). But, the change does affect end-user code that uses TIdTCPClient directly (as this WebSocket code is doing). In that case, the user is (and always has been) responsible for setting PassThrough as they need, but this WebSocket code is not doing that. When connecting to a secure URL, it assumes that PassThrough has been set to False by the user before TIdSimpleWebSocketClient.Connect() is called, rather than forcing it to False. And PassThrough is certainly not being set to False if TIdSimpleWebSocketClient needs to auto-create its own SSLIOHandler object.
TIdSimpleWebSocketClient.Connect() should internally be setting PassThrough := not lSecure; before calling inherited Connect. I have reported this as a bug to the author for you:
#10: TIdSimpleWebSocketClient TLS error - 400 Bad request, the plain HTTP request was sent to HTTPS port
In the meantime, until the author fixes this bug, you can simply assign your own SSLIOHandler component to the TIdSimpleWebSocketClient.IOHandler property and set it to PassThrough=False before calling TIdSimpleWebSocketClient.Connect() with a wss: URL.

How to determine which TLS/SSL protocol was negotiated when using sslvSSLv23?

I am using TIdSSLIOHandlerSocketOpenSSL to open a TLS/SSL connection. I currently want to support tls 1.0 to 1.2.
I initialize the IOHandler like this.
TIdSSLIOHandlerSocketOpenSSL(FSocket.IOHandler).SSLOptions.SSLVersions := [sslvTLSv1_2,sslvTLSv1_1, sslvTLSv1];
After the connection is made, how can I get which protocol was negotiated for the connection? (Both for ensuring the configuration of both the client and test server is correct, and eventually for statistics purpose).
I checked SSLContext.Method after the connection, but it still shows sslvSSLv23 after the connection. SSLContext.SSLVersions shows [sslvTLSv1_2,sslvTLSv1_1, sslvTLSv1].
So how do I get that information?
The specific negotiated protocol is in the TIdSSLIOHandlerSocketOpenSSL.SSLSocket.Cipher.Version property after the SSL/TLS session is established. OpenSSL also has a SSL_get_version() function (which Indy does not use, but you can call directly).

Create TCP TUNNELING system using Indy

Hi is it possible to create intermediary application which will act as tcp proxy server? It would be made of two components. IdTCPServer and IdTCPClient. The idea is:
Application > connects to IdTCPServer > all data is redirected to > IdTCPClient which is connected to the destination.
And the data received by TCPClient will be redirected to the IdTCPServer and Application.
I made such simple app, and it works in HTTP requests, but it fails when I tried to use it for RDP Client ( I got error that Protocol is wrong). Is it even possible? I use ReadByte method, and each single byte is sent to the other IOHandler.
I would like to create some sort of virtual tcp channel which would allow connections over NAT.
I wasn't clear enough. What I want to achieve is something like this:
RDP Server < IdTCPClient <> IdTCPclient > NAT > IdTCPServer < RDPClient.
Application > connects to IdTCPServer > all data is redirected to > IdTCPClient which is connected to the destination.
And the data received by TCPClient will be redirected to the IdTCPServer and Application.
In fact, Indy has a component specifically for that very purpose - TIdMappedPortTCP.
Set its MappedHost and MappedPort properties to point at the intended destination, then activate it, and all inbound connections will automatically be directed to the destination, and data passed back and forth in both directions.
I was going to add just a comment, but don't have enough points for that.
Your request says you want to "redirect", for which Remy supplied the answer.
However, your description sounds like you want to pass the data yourself (man-in-the-middle). RDP contains some guards against that, though earlier versions may have been more open to it.
You may want to specify the question more tightly if actual redirect is not what you are looking for.

Delphi Redirect SSL tcp data to other port no ssl

I am working with D5 ( thats a fact ). I have Indy9 installed.
I'm trying to receive data of IdMappedPortTCP on port 8041 (SSL) and redirect the data to a Tserversocket on port 8040. So I will have support of SSL over Tserversocket.
I use the following code:
var
masterdir:String;
begin
masterdir:=Extractfilepath(paramstr(0));
IdMappedPortTCP1.Active:=false;
datamodule2.IdMappedPortTCP1.MappedHost:='192.168.0.3';
datamodule2.IdMappedPortTCP1.MappedPort:=8041;
datamodule2.IdMappedPortTCP1.DefaultPort:=8040;
IdServerIOHandlerSSL1.SSLOptions.RootCertFile:=masterdir+'mycert.pem';
IdServerIOHandlerSSL1.SSLOptions.CertFile:=masterdir+'mycert.pem';
IdServerIOHandlerSSL1.SSLOptions.KeyFile:=masterdir+'key.pem';
IdMappedPortTCP1.IOHandler:=IdServerIOHandlerSSL1;
IdMappedPortTCP1.Active:=true;
end;
If I don't use SSL everything is fine. But when I use SSL teh request never comes to the port 8040 encrypted and I need it not encrypted so I can proccess it.
It is not clear from your description whether TServerSocket is using SSL on port 8040 or not. It makes a big difference in how you set up TIdMappedPortTCP. However, from your description, you have the MappedPort and DefaultPort property assignments backwards, at least. DefaultPort is the port that TIdMappedPortTCP listens on, so it should be 8041. MappedPort is the port that TIdMappedPortTCP connects to, so it should be 8040.
It is not common to have unencrypted and encrypted connections on the same port. Most protocols use separate ports. Is that the case here? Is port 8040 unencrypted, and port 8041 encrypted?
If you want TIdMappedPortTCP to accept encrypted and unencrypted clients on separate ports, you need to add 2 entries to the TIdMappedPortTCP.Bindings collection, one for each port, and not use the DefaultPort property at all. In the TIdMappedPortTCP.OnConnect event, you can detect which port the client connected to, and then configure the AThread.OutboundClient accordingly before it connects to TServerSocket.
It is not wise to have unencrypted and encrypted clients connect to the same port. In that scenario, you have to sniff the first few bytes to know if the client is sending an SSL handshake or not, and then act accordingly. It is easier to just use separate ports instead. However, some protocols do allow a client to connect to an unencrypted port and then send a command to activate encryption when needed. In that scenario, you would only need 1 port in TIdMappedPortTCP, so you can either define 1 Binding or use DefaultPort.
TIdMappedPortTCP is primarily intended to be a straight passthrough of raw bytes back and forth between the client and the target server. If TServerSocket is using SSL and you want the client to talk to TServerSocket using SSL properly, you should not be using TIdServerIOHandlerSSL at all. Let TIdMappedPortTCP pass the client's raw encrypted data as-is to TServerSocket, and vice versa. They should establish a secure session with each other, not with you. This is especially important if either one of them performs peer identity validation.
If you need to process encrypted data that is being exchanged between the client and TServerSocket, you have to decrypt and re-encrypt the data as it passes through TIdMappedPortTCP (which means you are acting as a man-in-the-middle attacker, which peer validation is meant to prevent). To do that, you have to establish separate SSL sessions between the client and TIdMappedPortTCP, and between TIdMappedPortTCP and TServerSocket. Assigning a TIdServerIOHandlerSSL to TIdMappedPortTCP only facilitates the session with the client. You have to manually setup a session with TServerSocket. To do that, you have to manually assign a new TIdSSLIOHandlerSocket object to the AThread.OutboundClient.IOHandler property in the OnConnect event. TIdMappedPortTCP will not handle that for you.
If, however, TServerSocket is not using SSL, and you are using TIdMappedPortTCP as an SSL gateway into TServerSocket, then you can skip the OutboundClient.IOHandler assignment, since you would only need 1 SSL session, between TIdMappedPortTCP and the client.
Now, with that said, there are some problems in Indy 9. The TIdSSLIOHandlerOpenSSL.PassThrough property is False by default (thus assuming encryption is initially active), and TIdServerIOHandlerSSL assumes that every accepted client connection is using SSL, even if it really is not. If an unencrypted client connects to TIdMappedPortTCP with TIdServerIOHandlerSSL assigned, the client will not be handled correctly. These issues were fixed in Indy 10. But in Indy 9, you will not be able to handle encrypted and unencrypted clients in the same TIdMappedPortTCP component. If you are only dealing with encrypted clients though, you won't run into a problem. Otherwise, create 2 TIdMappedPortTCP components, one listening on an unencrypted port, the other listening on an encrypted port. They can share the same event handlers. If needed, you can use the AThread.Connection.Socket.Binding.Port property to know which port the client is connected to.

Connect with TTcpClient through a http proxy

How can i connect to a server through a http proxy server in delphi?
What about SOCKS5 proxy?
Google doesn't have any suggestion!
If you're using Indy (highly recommended), then try using a TIdConnectThroughHttpProxy object from the IdConnectThroughHttpProxy unit. It's a descendant of TIdIOHandler, so connect an instance of that class to your client object's IOHandler property. To connect through a Socks server instead, use TIdSocksInfo, in IdSocks.
If you're set on doing it manually, without the aid of a protocol library like Indy, then connect your TTcpClient object to the proxy server's address instead of the real destination, and then send your commands there. The proxy server knows where to send the request either because you issue a CONNECT command to it, or because you specify a full URL (instead of just the path portion) in the GET request. (The HTTP spec demonstrates the latter.) The response you'll get should be forwarded from the destination server, unless the proxy server has an error itself.
I think you can do it using Indy. You may find information in the Indy in Depth ebook.
Hope this helps.

Resources