Recent

Author Topic: Indy and TIdMappedPortTCP data manipolation  (Read 4638 times)

xinyiman

  • Hero Member
  • *****
  • Posts: 2193
    • Lazarus and Free Pascal italian community
Indy and TIdMappedPortTCP data manipolation
« on: December 11, 2021, 01:39:29 pm »
Hi everyone, I wanted to manipulate data in transit over a TIdMappedPortTCP based connection.

Client <-> TIdMappedPortTCP <--> TIdMappedPortTCP <-> server

Ultimately the purpose is to encrypt the connection between the two TIdMappedPortTCP components.

I don't want to use OpenSSL, I want to use Xor-El user's cryptographic components, so as not to depend on external dlls.

Someone explain to me how I can manipulate the data passing between the two components?

I tried in the IdMappedPortTCP1Execute event

to read the data with

msg := BytesToString(TIdMappedPortContext(AContext).NetData);

to manipulate and retransmit them with

                msg := ReverseString(msg);
                TIdMappedPortContext(AContext).NetData := ToBytes(msg);

But they don't work, messages are delayed by one sending. Can anyone help me?
Thank you
Win10, Ubuntu and Mac
Lazarus: 2.1.0
FPC: 3.3.1

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1101
    • Lebeau Software
Re: Indy and TIdMappedPortTCP data manipolation
« Reply #1 on: December 13, 2021, 10:18:10 pm »
Hi everyone, I wanted to manipulate data in transit over a TIdMappedPortTCP based connection.

Client <-> TIdMappedPortTCP <--> TIdMappedPortTCP <-> server

Ultimately the purpose is to encrypt the connection between the two TIdMappedPortTCP components.

The best way to handle that is to have the connection between the two TIdMappedPortTCPs using appropriate TIdSSLIOHandlerSocketBase-derived classes on both ends that know how to encrypt/decrypt how you want.

For the outgoing TIdMappedPortTCP #1, in its TIdMappedPortTCP.OnConnect event, which is fired before the TCP connection is opened to the next server, you can assign an appropriate TIdSSLIOHandlerSocketBase-derived object to the TIdMappedPortContext(AContext).OutboundClient.IOHandler property.  Make sure its PassThrough property is set to False before you need to exchange any encrypted data.  You can do that immediately in the OnConnect event, or if you want to send a STARTTLS-style command first then you can set PassThrough=False in the TIdMappedPortTCP.OnOutboundConnect event instead, which is fired immediately after the OutboundClient is connected.

For the incoming TIdMappedPortTCP #2, assign an appropriate TIdServerIOHandlerSSLBase-derived object to the TIdMappedPortTCP.IOHandler property before activating the server, and make sure it overrides Accept() to return an appropriate TIdSSLIOHandlerSocketBase-derived object.  Make sure its PassThrough property is set to False before you need to exchange any encrypted data.
Accept() can set PassThrough=False immediately, or for STARTTLS-style handling you can use the TIdMappedPortTCP.OnBeforeConnect event, which is fired after a new TCP client is accepted and before TIdMappedPortTCP tries to connect to the next server. Type-cast the AContext.Connection.IOHandler property to TIdSSLIOHandlerSocketBase to access its PassThrough property.

I don't want to use OpenSSL, I want to use Xor-El user's cryptographic components, so as not to depend on external dlls.

OpenSSL is simply Indy's default implementation of SSL/TLS, but Indy is not dependent on OpenSSL specifically (at least in this situation).  The SSLIOHandler architecture is abstract enough that you can write your own SSLIOHandler classes for any SSL/TLS engine you want, and then you can assign those classes to Indy at runtime.

Someone explain to me how I can manipulate the data passing between the two components?

If you don't want to go the SSLIOHandler route, TIdMappedPortTCP does offer an alternative:

- for data flowing from a connected client to the associated outbound connection, you can modify raw bytes stored in the TIdMappedPortContext(AContext).NetData property in the TIdMappedPortTCP.OnExecute event. Whatever data is left in the NetData when the event handler exits will be sent to the next server.

- for data flowing from an outbound connection to the associated connected client, you can modify raw bytes stored in the TIdMappedPortContext(AContext).NetData property in the TIdMappedPortTCP.OnOutboundData event. Whatever data is left in the NetData when the event handler exits will be sent to the client.

So, in your example, TIdMappedPortTCP #1 would encrypt in OnExecute and decrypt in OnOutboundData, whereas TIdMappedPortTCP #2 would decrypt in OnExecute and encrypt in OnOutboundData.

Just note that NetData is whatever arbitrary bytes are available at the time the event is fired.  You can't assume anything about the message structure of the bytes.  If you need that, you have to buffer the bytes yourself and then parse out whole messages from your buffer as needed.

I tried in the IdMappedPortTCP1Execute event
...
But they don't work

Why are you using strings to handle encrypted data? Why are you reversing those strings? That is certainly not any kind of encryption at all.

In any case, you are just reading and reversing arbitrary bytes (and without any regard to charset encodings).  In order for the receiver to be able to re-reverse that data properly, your event handlers would have to add a custom header to each NetData to indicate how many bytes are being reversed per event.  The receiver could then read a header, read the indicated number of bytes and reverse them, then repeat...

messages are delayed by one sending. Can anyone help me?

Meaning what exactly?
« Last Edit: December 16, 2021, 06:02:06 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

xinyiman

  • Hero Member
  • *****
  • Posts: 2193
    • Lazarus and Free Pascal italian community
Re: Indy and TIdMappedPortTCP data manipolation
« Reply #2 on: December 15, 2021, 10:44:54 pm »
Thanks for the explanation. I'll try to treasure it. Using the string was just for preliminary testing.
Thanks a lot anyway
Win10, Ubuntu and Mac
Lazarus: 2.1.0
FPC: 3.3.1

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1101
    • Lebeau Software
Re: Indy and TIdMappedPortTCP data manipolation
« Reply #3 on: December 16, 2021, 06:03:38 pm »
Thanks for the explanation. I'll try to treasure it.

I have updated the description, I found some mistakes in what I had posted earlier.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

xinyiman

  • Hero Member
  • *****
  • Posts: 2193
    • Lazarus and Free Pascal italian community
Re: Indy and TIdMappedPortTCP data manipolation
« Reply #4 on: January 23, 2022, 05:07:59 pm »
Sorry for the delay in replying. Do you mean something like this?

Code: Pascal  [Select][+][-]
  1. unit usecuretunnel;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, IdSSLOpenSSL, IdMappedPortTCP;
  9.  
  10. type
  11.  
  12.     TSecureTunnelType = (sttClient, sttServer);
  13.  
  14.     { TSecureTunnel }
  15.  
  16.     TSecureTunnel = class
  17.     private
  18.            FIOHandlerSSL     : TIdServerIOHandlerSSLOpenSSL;
  19.            FTCPMappedPort    : TIdMappedPortTCP;
  20.            FSecureTunnelType : TSecureTunnelType;
  21.            procedure MyOnOutboundConnect(AContext: TIdContext);
  22.            procedure MyOnConnect(AContext: TIdContext);
  23.     public
  24.           constructor Create(DefaultPort : integer; MappedHost : string; MappedPort : integer; TypeOfTunnel : TSecureTunnelType);
  25.           destructor Free;
  26.     end;
  27.  
  28. implementation
  29.  
  30. { TSecureTunnel }
  31.  
  32. procedure TSecureTunnel.MyOnOutboundConnect(AContext: TIdContext);
  33. begin
  34.      if (FSecureTunnelType = sttClient) then
  35.      begin
  36.           FTCPMappedPort(AContext).OutboundClient.IOHandler               := FIOHandlerSSL;
  37.           TIdSSLIOHandlerSocketBase(FTCPMappedPort.IOHandler).PassThrough := False;
  38.      end;
  39. end;
  40.  
  41. procedure TSecureTunnel.MyOnConnect(AContext: TIdContext);
  42. begin
  43.      if (FSecureTunnelType = sttServer) then
  44.      begin
  45.           FTCPMappedPort(AContext).OutboundClient.IOHandler               := FIOHandlerSSL;
  46.           TIdSSLIOHandlerSocketBase(FTCPMappedPort.IOHandler).PassThrough := False;
  47.      end;
  48. end;
  49.  
  50. constructor TSecureTunnel.Create(DefaultPort: integer; MappedHost: string;
  51.   MappedPort: integer; TypeOfTunnel: TSecureTunnelType);
  52. begin
  53.      FIOHandlerSSL                    := TIdServerIOHandlerSSLOpenSSL.Create(nil);
  54.      FTCPMappedPort                   := TIdMappedPortTCP.Create;
  55.      FTCPMappedPort.DefaultPort       := DefaultPort;
  56.      FTCPMappedPort.MappedHost        := MappedHost;
  57.      FTCPMappedPort.MappedPort        := MappedPort;
  58.      FSecureTunnelType                := TypeOfTunnel;
  59.      FTCPMappedPort.OnOutboundConnect := @MyOnOutboundConnect;
  60.      FTCPMappedPort.OnConnect         := @MyOnConnect;
  61. end;
  62.  
  63. destructor TSecureTunnel.Free;
  64. begin
  65.      if Assigned(FTCPMappedPort) then
  66.      begin
  67.           FTCPMappedPort.Free;
  68.           FTCPMappedPort:=nil;
  69.      end;
  70.      if Assigned(FIOHandlerSSL) then
  71.      begin
  72.           FIOHandlerSSL.Free;
  73.           FIOHandlerSSL:=nil;
  74.      end;
  75. end;
  76.  
  77. end.
  78.  
Win10, Ubuntu and Mac
Lazarus: 2.1.0
FPC: 3.3.1

 

TinyPortal © 2005-2018