tags:

views:

140

answers:

2

Hi ,

I have a public server(configured with indy 10) . some unknown clients are sending thousands of no content messages that it change the server's cpu usage to 50% . i have no firewall on my server , so i tried to block the unknown clients with this codes :

This is a function that works with a Timer :

var
  i, j: integer;
begin
  IX2 := IX2 + 1;
  SetLength(ClientIPs, IX2);
  ClientIPs[IX2 - 1] := StrIP;
  j := 0;
  for i := low(ClientIPs) to high(ClientIPs) do
  begin
    Application.ProcessMessages;
    if ClientIPs[i] = StrIP then
      j := j + 1;
  end;
  if j > 10 then
  begin
    Result := false;
    exit;
  end;
  Result := true;

And it's my Timer code :

  //Reset filtering measures
  IX2 := 0;
  SetLength(ClientIPs, 0);

So i use it in OnExecute event :

  LogIP := AContext.Connection.Socket.Binding.PeerIP;

  if IPFilter(LogIP) <> true then
  begin
    AContext.Connection.disconnect;
    exit;
  end;

  //Get Data *********
  Data := AContext.Connection.IOHandler.ReadLn();

finally , if a client sends many message in a short time , it will be disconnect . but there is a problem . in fact , after client disconnection , the Onexecute event is still working and i can not stop the operation Fully .anyway i need to block some IPs completely .

Thank you

+2  A: 

The OnConnect event would be a better place to disconnect blacklisted IPs. The only reason to do the check in the OnExecute event is if the IP is not being blacklisted until after OnConnect has already been fired.

As for why OnExecute keeps running after you disconnect - the only way that can happen is if your OnExecute handler has a try..except block that is catching and discarding Indy's internal notifications. Any exception handling you do needs to re-raise EIdException-derived exceptions so the server can process them.

Remy Lebeau - TeamB
Hi , Thanks for response . but i'm not using try/except !
Kermia
Then please show your actual OnExecute code. You are not handling disconnects correctly in it.
Remy Lebeau - TeamB
Hi , I did Mr Lebeau . this is my actual OnExecute code : LogIP := AContext.Connection.Socket.Binding.PeerIP; if IPFilter(LogIP) <> true then begin AContext.Connection.disconnect; exit; end; //Get Data ********* Data := AContext.Connection.IOHandler.ReadLn();So , How can i handling disconnects correctly ?Thank you
Kermia
Did you verify that ReadLn() is actually being called? If what you showed earlier is the actual implementation of the IPFilter() function, then that code is not even remotely thread-safe, and thus can cause all kinds of problems, including deadlocks and crashes. It looks like the code is simply trying to prevent the same client IP from establishing more than 10 simultaneous connections, is that right? If so, then the implementation can be greatly simplified and stablized by simply looping through the server's own Contexts list instead of maintaining your own list. I have posted the code.
Remy Lebeau - TeamB
+1  A: 

Followup to my earlier comment:

function TForm1.IPFilter(const StrIP: string): Boolean;
var 
  i, j: integer; 
  list: TList;
begin 
  j := 0; 
  list := IdTCPServer1.Contexts.LockList;
  try
    for i := 0 to list.Count-1 do 
    begin 
      if TIdContext(list[i]).Binding.PeerIP = StrIP then
        Inc(j); 
    end; 
    Result := j <= 10; 
  finally
    IdTCPServer1.Contexts.UnlockList;
  end;
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
begin
  // the simpliest way to force a disconnect and stop
  // the calling thread is to raise an exception...
  if not IPFilter(AContext.Binding.PeerIP) then
    Abort();

  // alternatively, if you call Disconnect(), make sure
  // the IOHandler's InputBuffer is empty, or else
  // AContext.Connection.Connected() will continue
  // returning True!...
  {if not IPFilter(AContext.Binding.PeerIP) then
  begin
    AContext.Connection.Disconnect;
    AContext.Connection.IOHandler.InputBuffer.Clear;
    Exit;
  end;}

  //Get Data ********* 
  Data := AContext.Connection.IOHandler.ReadLn(); 
end;
Remy Lebeau - TeamB
Thank you Mr Lebeau
Kermia