Using Indy Internet Direct for Delphi, with Lazarus on Linux, I developed an application which acts as a proxy with the purpose of redirecting clients to different content based on their IP address.
To do this, I used the TIdMappedPortTCP
object.
OnConnect
notify event, and change the AContext.Binding.Port
.OnBeforeConnect
notify event instead.Binding.Port
but on OnContextCreate
.TIdMappedPortTCP.MappedPort
As an example, I have attempt number 2, which overrides OnBeforeConnect
. I assume this attempt failed as AContext.Connection.Connected
is already true
at this stage, but I cannot find a way to modify It earlier than this.
procedure TMapperApplication.OnBeforeConnect(AContext: TIdContext);
var
IP, Host: string;
var
I: integer;
begin
// List
Inc(ConnectionCount);
AddConnection(AContext);
// Write
WriteDate;
IP := AContext.Binding.PeerIP;
Host := GStack.HostByAddress(IP);
TConsole.TextColor := TConsoleColor.LightMagenta;
TConsole.Write := 'Incoming connection from ';
TConsole.TextColor := TConsoleColor.LightBlue;
TConsole.Write := Format('"%S" (%S) on port %D', [Host, IP, AContext.Binding.Port]);
WriteNewLn;
// Common date
WriteDate;
// Redirect port
for I := 0 to High(Servers) do
if IP = Servers[I].Source then
begin
AContext.Binding.IP:=Servers[I].Host;
AContext.Binding.Port:=Servers[I].Port;
TConsole.TextColor := TConsoleColor.Yellow;
TConsole.Write := 'Mapped connection to ';
TConsole.ResetStyle;
TConsole.WriteLn:=Format('%S:%D', [Servers[I].Host, Servers[I].Port]);
ResetNewLn;
Exit;
end;
// Default mapping
if EnableDefault then
begin
AContext.Binding.IP:=Servers[I].Host;
AContext.Binding.Port:=Servers[I].Port;
Mapper.Active:=true;
TConsole.WriteLn:='Mapped connection to default host.';
Exit;
end;
// Mapping failed
TConsole.TextColor:=TConsoleColor.Red;
TConsole.WriteLn:='Connection was dropped. No mapping found.';
AContext.Connection.Disconnect;
TConsole.ResetStyle;
end;
After I tackle this issue, I plan to replace the IP address detection, and use a way to detect server1.site.com
and server2.site.com
, but I'm unsure If that's even possible in Delphi with the available libraries. I tried GStack.HostByAddress(AContext.Binding.PeerIP)
, but that returns an empty string. A problem for another time.
I would have also searched www.indyproject.org
, but It seems the web server is down at the moment. The downloads do not work. There is also this, but It does not provide any information useful for this problem.
I also found this old forum, but unfortunately the solution seems to be outdated as TIdMappedPortThread
is an undefined declaration and is not used in the TIdMappedPortTCP
. Also this, but It's also outdated.
So currently, I have exhausted all the ideas I have. Maybe creating a custom TIdMappedPortTCP
could help? But I'm unsure at this point.
The older solution you found is for Indy 9, but the same approach still applies in Indy 10. Simply replace TIdMappedPortThread
with TIdMappedPortContext
in Indy 10.
You cannot change the AContext.Binding.IP
/Port
, that is the listening IP/port where the client connected to your proxy.
To change where the proxy forwards to next on a per-connection basis (ie, not using the MappedHost
/MappedPort
properties), then you have to use the OnConnect
event not the OnBeforeConnect
event, and cast AContext
to TIdMappedPortContext
, then cast its OutboundClient
to TIdTCPClient
, and then set its Host
and Port
as needed.
procedure TMapperApplication.OnConnect(AContext: TIdContext);
begin
...
with TIdTCPClient(TIdMappedPortContext(AContext).OutboundClient) do
begin
Host := ...;
Port := ...;
end;
...
end;