【问题标题】:IP Black List TcpServerIP 黑名单 TcpServer
【发布时间】:2017-05-01 11:08:26
【问题描述】:

如何限制每个 ip 的连接数?我已经尝试过此代码how to block unknown clients in indy (Delphi),但如果我的服务器被淹没,我将无法连接。来自 Remy 的代码只是阻止 CPU 使用 100% 并使用更多内存。但是来自洪水的连接在 tcpserver 上仍然存在,我无法连接到服务器。所以我的问题是,我如何在 onconnect 之前限制连接,使用 tcpserver 接受一些东西?也许挂钩接受功能并尝试限制连接?

【问题讨论】:

  • 您可能最好在您的硬件级别阻止传入连接,例如在防火墙中。如果您的问题是攻击者使您的服务器超载,那么无论您编写多少代码,这些数据在技术上仍然会进入您的应用程序。毕竟,这就是 DDoS 工作的本质。
  • 是的,我写了一个小应用程序,它只创建 9999 个客户端并连接并冻结我的系统。所以我需要在不使用防火墙的情况下限制每个 ip 的连接。
  • 为了扩展我之前的评论,有许多硬件防火墙明确设计用于防止这种确切性质的 DDoS 攻击。大多数标准/廉价路由器都无法处理。我什至在商务级 SonicWall 路由器上测试了 DDoS,据说该路由器具有 DDoS 防护功能 - 英国的一位朋友在我失去互联网之前只花了 3 秒钟的时间进行攻击,我不得不上楼重新启动它。

标签: delphi


【解决方案1】:

如何限制每个 ip 的连接数?

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

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

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

洪水管理确实需要由防火墙或路由器/负载平衡器来处理,而不是在服务器应用程序本身中。如果这对您来说是不可接受的,那么至少仅在 Windows 上,一个选项可能是编写一个自定义的 TIdServerIOHandlerStack 派生组件,该组件覆盖虚拟 Accept() 方法来调用 WinSock 的 WSAAccept() 函数,它为您提供回调可以在连接离开接受队列之前拒绝连接,因此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;

然后您可以在激活服务器之前将TMyServerIOHandler 的实例分配给TIdTCPServer.IOHandler 属性。

【讨论】:

  • 我的代码有这个错误 [dcc32 Error] Unit1.pas(372): E2003 Undeclared identifier: 'IOHandlerSocketClass'
  • 现在是 [dcc32 Error] Unit1.pas(1682): E2010 Incompatible types: 'TIdServerIOHandler' and 'class of TMyIdServerIOHandler' when try assign IdTCPServer1.IOHandler := TMyIdServerIOHandler;
  • @DouglasRuiz TIdTCPServer.IOHandler 属性是指向对象的指针,而不是类类型。您必须先 Create TMyIdServerIOHandler 对象才能分配它:IdTCPServer1.IOHandler := TMyIdServerIOHandler.Create(IdTCPServer1);
  • 我有这个错误无法访问 LBinding.SetHandle(LAcceptedSocket) 上的受保护符号 TIdSocketHandle.SetHandle;行:/我使用的是delphi 10.1 berlin
  • 我添加了代码 IdTCPServer1.IOHandler := TMyServerIOHandler.Create(IdTCPServer1);,以及函数接受的一些消息,但我的连接从未触发消息:/ 所以我的连接不通过接受函数传递跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-03
  • 1970-01-01
  • 2010-09-11
  • 1970-01-01
  • 1970-01-01
  • 2014-09-11
  • 1970-01-01
相关资源
最近更新 更多