2017-03-15 101 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);' –