尝试阻止Indy连接传入

问题描述

我打算阻止某些客户端连接到我的服务器。我有以下代码段:

procedure TMain.WebServiceConnect(AContext:TIdContext);

Var
  IP:String;

begin
  try
    IP:=AContext.Binding.PeerIP;
    if Allowlist.IndexOf(IP)=-1 then Begin;
      if Blocklist.IndexOf(IP)>-1 then Begin;
        LogWrite('Blocking IP "'+IP+'"!',Detailed);
        LogRequest(IP,'*BLOCKED*');
        AContext.Connection.disconnect;
      End;
    End;
  except
    ON E:Exception do
      LogWrite('"'+E.Message+'" while connection-check on blocklist',Detailed);
  end;
end;

procedure TMain.WebServiceReceive(AContext:TIdContext; ARequestInfo:TIdHTTPRequestInfo; AResponseInfo:TIdHTTPResponseInfo);

begin
  try
    try
      LogWrite('Handling connection from '+ARequestInfo.RemoteIP,Debug);
      AResponseInfo.ResponseNo:=401;
      ProcessWebRequest(AContext,ARequestInfo,AResponseInfo);
      LogWrite('Closing connection to '+ARequestInfo.RemoteIP,Debug);
    except
      ON E:Exception do
        LogWrite('"'+E.Message+'" while handling request!',verbose,FALSE);
    End;
  finally
  End;
End;

但是我看到两个事件都是从被阻止的IP触发的!我看到“被阻止的”日志行,但是看来AContext.Connection.disconnect的作用不符合预期。

怎么了?

解决方法

如果OnCommand...事件已关闭服务器的OnConnect事件,则无法为给定的客户端连接触发该事件。在触发TIdRequestInfo事件之前,服务器将无法读取客户端的请求数据以填充OnCommand...对象。

因此,您可能没有像预期的那样实际致电Disconnect(),或者是您误诊了该问题。

例如,在日志消息中,除了AContext.Binding.PeerPort之外,还尝试包括AContext.Binding.Handle甚至是PeerIP,以确保日志消息实际上属于同一客户端连接。单独使用PeerIP不足以唯一地标识单个连接。

也就是说,在极少数情况下Disconnect()实际上没有关闭连接,您可以通过引发异常(例如通过SysUtils.Abort())来强制断开连接,以便服务器终止连接。调用线程并关闭套接字。

另外,谈到异常,您应该重新引发用except捕获的任何异常(或者至少是从EIdException派生的任何Indy异常),让服务器处理它。 / p>

尝试更多类似的方法:

procedure TMain.WebServiceConnect(AContext:TIdContext);
var
  IP: String;
  Port: TIdPort;
begin
  try
    IP := AContext.Binding.PeerIP;
    Port := AContext.Binding.PeerPort;
    if Allowlist.IndexOf(IP) = -1 then begin
      if Blocklist.IndexOf(IP) > -1 then begin
        LogWrite('Blocking IP "' + IP + ':' + IntToStr(Port) + '"!',Detailed);
        LogRequest(IP,'*BLOCKED*');
        AContext.Connection.Disconnect;
        SysUtils.Abort;
      end;
    end;
  except
    on E: Exception do begin
      if not (E is EAbort) then
        LogWrite('"' + E.Message + '" while connection-check on blocklist',Detailed);
      raise;
    end;
  end;
end;

procedure TMain.WebServiceReceive(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  IP: String;
  Port: TIdPort;
begin
  try
    IP := AContext.Binding.PeerIP;
    Port := AContext.Binding.PeerPort;
    LogWrite('Handling connection from ' + IP + ':' + IntToStr(Port),Debug);
    AResponseInfo.ResponseNo := 401;
    ProcessWebRequest(AContext,ARequestInfo,AResponseInfo);
    LogWrite('Closing connection to ' + IP + ':' + IntToStr(Port),Debug);
  except
    on E: Exception do begin
      LogWrite('"' + E.Message + '" while handling request!',verbose,FALSE);
      raise;
    end;
  end;
end;