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.
Some of the things I tried were:
- To set the
OnConnectnotify event, and change theAContext.Binding.Port. - The one above, but the
OnBeforeConnectnotify event instead. - Again to change the
Binding.Portbut onOnContextCreate. - Changing the
TIdMappedPortTCP.MappedPort
Attempt
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;
Why use IP to differentiate the client?
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.
Research
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
TIdMappedPortThreadwithTIdMappedPortContextin 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/MappedPortproperties), then you have to use theOnConnectevent not theOnBeforeConnectevent, and castAContexttoTIdMappedPortContext, then cast itsOutboundClienttoTIdTCPClient, and then set itsHostandPortas needed.