Search code examples
delphihttp-redirectdelphi-5indy-9

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.


Solution

  • 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.