2017-03-15 57 views
3

我如何限制每个ip的连接?我试过这个代码how to block unknown clients in indy (Delphi),但如果我的服务器被淹没,我无法连接。来自雷米的代码只是防止CPU使用100%并使用更多内存。但连接从洪水仍然活着在tcpserver和我无法连接到服务器。所以我的问题是,如何限制onconnect之前的连接,接受使用tcpserver的东西?也许钩接受功能,并尝试限制连接?IP黑名单TcpServer

+1

您可能最好是阻止硬件级别的传入连接,例如在防火墙中。如果您的问题是攻击者重载您的服务器,那么您写入的代码数量无关紧要,这些数据在技术上仍然在进入您的应用程序。毕竟,这就是DDoS的工作原理。 –

+0

是的,我编写了一个只创建9999个客户端并连接并冻结我的系统的小应用程序。所以我需要限制每个ip的连接而不使用防火墙。 –

+0

为了扩展我之前的评论,有很多硬件防火墙明确设计用于防止这种确切性质的DDoS攻击。大多数标准/廉价路由器无法处理它。在英国的朋友只花了攻击之前3秒钟我失去了互联网,我不得不上楼和身体重新启动它 - 我甚至商务舱SonicWall的路由器,据称有DDoS攻击防护上测试DDoS攻击。 –

回答

5

如何限制每个ip的连接?

你已经知道答案了,因为那正是the other code正在做的事情。

如果我的服务器被淹没,我无法连接。

其他代码的目的仅仅是将客户端IP地址限制为最多10个同时连接,而不是防止泛滥或降低CPU/RAM使用率。除非停用服务器或设置其MaxConnections属性,否则无法阻止不需要的客户端连接到服务器。除此之外,你所能做的就是尽快断开不需要的客户端,你可以在服务器的OnConnect事件中做这些事情。但是如果你被洪水淹没,那需要花费一些时间来处理,特别是如果你不断地锁定和解锁服务器的列表,这将最终序列化服务器的内部线程。

洪水管理确实需要由防火墙或路由器/负载均衡器来处理,而不是在服务器应用程序本身。如果这是不是至少在Windows上接受你,那么只有,一个选择可能是编写覆盖虚拟Accept()方法调用的WinSock的WSAAccept()功能,它提供了可以使用之前拒绝连接回调的自定义TIdServerIOHandlerStack衍生成分他们离开接受队列,因此他们不会被TIdTCPServer看到。例如:

type 
    TMyServerIOHandler = class(TIdServerIOHandlerStack) 
    public 
    function Accept(ASocket: TIdSocketHandle; AListenerThread: TIdThread; AYarn: TIdYarn): TIdIOHandler; override; 
    end; 

function MyConditionFunc(lpCallerId, lpCallerData: LPWSABUF; lpSQOS, lpGQOS: LPQOS; lpCalleeId, lpCalleeData: LPWSABUF; g: PGROUP dwCallbackData: DWORD_PTR): Integer; stdcall; 
begin 
    if (the address stored in lpCallerId is blocked) then 
    Result := CF_REJECT 
    else 
    Result := CF_ACCEPT; 
end; 

type 
    TIdSocketHandleAccess = class(TIdSocketHandle) 
    end; 

function TMyServerIOHandler.Accept(ASocket: TIdSocketHandle; AListenerThread: TIdThread; AYarn: TIdYarn): TIdIOHandler; 
var 
    LIOHandler: TIdIOHandlerSocket; 
    LBinding: TIdSocketHandle; 
    LAcceptedSocket: TIdStackSocketHandle; 
begin 
    Result := nil; 
    LIOHandler := TIdIOHandlerStack.Create(nil); 
    try 
    LIOHandler.Open; 
    while not AListenerThread.Stopped do 
    begin 
     if ASocket.Select(250) then 
     begin 
     LBinding := LIOHandler.Binding; 
     LBinding.Reset; 
     LAcceptedSocket := WSAAccept(ASocket.Handle, nil, nil, @MyConditionFunc, 0); 
     if LAcceptedSocket <> Id_INVALID_SOCKET then 
     begin 
      TIdSocketHandleAccess(LBinding).SetHandle(LAcceptedSocket); 
      LBinding.UpdateBindingLocal; 
      LBinding.UpdateBindingPeer; 
      LIOHandler.AfterAccept; 
      Result := LIOHandler; 
      LIOHandler := nil; 
      Break; 
     end; 
     end; 
    end; 
    finally 
    FreeAndNil(LIOHandler); 
    end; 
end; 

然后你就可以激活服务器之前分配的TMyServerIOHandlerTIdTCPServer.IOHandler属性的实例。

+0

我的代码有这个错误[dcc32 Error] Unit1.pas(372):E2003 Undeclared identifier:'IOHandlerSocketClass' –

+0

now is [dcc32 Error] Unit1.pas(1682):E2010 Incompatible types:'TIdServerIOHandler'and'class TMyIdServerIOHandler'当尝试分配IdTCPServer1.IOHandler:= TMyIdServerIOHandler; –

+0

@DouglasRuiz了'TIdTCPServer.IOHandler'属性是一个指向对象的指针,而不是一个类类型。你必须创建一个'TMyIdServerIOHandler'对象,然后才能指定它:'IdTCPServer1.IOHandler:= TMyIdServerIOHandler.Create(IdTCPServer1);' –