如何在indy中阻止未知客户端(Delphi)

时间:2010-08-06 07:27:38

标签: delphi indy

我有一个公共服务器(配置indy 10)。一些未知的客户端正在发送数以千计的无内容消息,它将服务器的CPU使用率更改为50%。我的服务器上没有防火墙,所以我试图使用以下代码阻止未知客户端:

这是一个与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;

这是我的计时器代码:

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

所以我在OnExecute事件中使用它:

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

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

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

最后,如果客户端在短时间内发送了许多消息,它将断开连接。但有一个问题 。事实上,在客户端断开连接之后,Onexecute事件仍在工作,我无法完全停止操作。但是我需要完全阻止某些IP。

谢谢

2 个答案:

答案 0 :(得分:5)

OnConnect事件是断开黑名单IP的更好地方。在OnExecute事件中进行检查的唯一原因是,在OnConnect已被触发之前,IP是否未被列入黑名单。

至于为什么OnExecute在你断开连接后继续运行 - 唯一可能发生的方法是你的OnExecute处理程序有一个try..except块,它正在捕获并丢弃Indy的内部通知。您执行的任何异常处理都需要重新引发EIdException派生的异常,以便服务器可以处理它们。

答案 1 :(得分:4)

跟进我之前的评论:

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;