main.pas

来自「FIR引擎最新源码+注册」· PAS 代码 · 共 1,441 行 · 第 1/3 页

PAS
1,441
字号
unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics,
  Controls, Forms, Dialogs, StdCtrls, JSocket, WinSock, ExtCtrls, ComCtrls,
  Menus, IniFiles, GateShare, Common;
type
  TUserSession = record
    Socket: TCustomWinSocket;
    sRemoteIPaddr: string;
    nSendMsgLen: Integer;
    nReviceMsgLen: Integer;
    bo0C: Boolean;
    dw10Tick: LongWord;
    nCheckSendLength: Integer;
    boSendAvailable: Boolean;
    boSendCheck: Boolean;
    dwSendLockTimeOut: LongWord;
    n20: Integer;
    dwUserTimeOutTick: LongWord;
    SocketHandle: Integer;
    sIP: string;
    MsgList: TStringList;
    dwConnctCheckTick: LongWord;
    dwReceiveTick: LongWord;
    dwReceiveTimeTick: LongWord;

    nReviceMsgLength: Integer;
    dwReceiveMsgTick: LongWord;
  end;
  pTUserSession = ^TUserSession;
  TSessionArray = array[0..GATEMAXSESSION - 1] of TUserSession;
  TFrmMain = class(TForm)
    ServerSocket: TServerSocket;
    MemoLog: TMemo;
    SendTimer: TTimer;
    ClientSocket: TClientSocket;
    Panel: TPanel;
    Timer: TTimer;
    DecodeTimer: TTimer;
    LbHold: TLabel;
    LbLack: TLabel;
    Label2: TLabel;
    StatusBar: TStatusBar;
    MainMenu: TMainMenu;
    MENU_CONTROL: TMenuItem;
    StartTimer: TTimer;
    MENU_CONTROL_START: TMenuItem;
    MENU_CONTROL_STOP: TMenuItem;
    MENU_CONTROL_RECONNECT: TMenuItem;
    MENU_CONTROL_CLEAELOG: TMenuItem;
    MENU_CONTROL_EXIT: TMenuItem;
    MENU_VIEW: TMenuItem;
    MENU_VIEW_LOGMSG: TMenuItem;
    MENU_OPTION: TMenuItem;
    MENU_OPTION_GENERAL: TMenuItem;
    MENU_OPTION_IPFILTER: TMenuItem;
    H1: TMenuItem;
    S1: TMenuItem;

    procedure MemoLogChange(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure SendTimerTimer(Sender: TObject);
    procedure TimerTimer(Sender: TObject);
    procedure DecodeTimerTimer(Sender: TObject);
    procedure ClientSocketConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocketDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocketError(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    procedure ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
    procedure ServerSocketClientConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocketClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocketClientError(Sender: TObject;
      Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
      var ErrorCode: Integer);
    procedure ServerSocketClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure StartTimerTimer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure MENU_CONTROL_STARTClick(Sender: TObject);
    procedure MENU_CONTROL_STOPClick(Sender: TObject);
    procedure MENU_CONTROL_RECONNECTClick(Sender: TObject);
    procedure MENU_CONTROL_CLEAELOGClick(Sender: TObject);
    procedure MENU_CONTROL_EXITClick(Sender: TObject);
    procedure MENU_VIEW_LOGMSGClick(Sender: TObject);
    procedure MENU_OPTION_GENERALClick(Sender: TObject);
    procedure MENU_OPTION_IPFILTERClick(Sender: TObject);
    procedure S1Click(Sender: TObject);
  private
    dwShowMainLogTick: LongWord;
    boShowLocked: Boolean;
    TempLogList: TStringList;
    nSessionCount: Integer;
    StringList30C: TStringList;
    dwSendKeepAliveTick: LongWord;
    boServerReady: Boolean;
    StringList318: TStringList;

    dwDecodeMsgTime: LongWord;
    dwReConnectServerTick: LongWord;
    procedure ResUserSessionArray();
    procedure StartService();
    procedure StopService();
    procedure LoadConfig();
    procedure ShowLogMsg(boFlag: Boolean);
    function IsBlockIP(sIPaddr: string): Boolean;
    function IsConnLimited(sIPaddr: string; SocketHandle: Integer): Boolean;
    function AddAttackIP(sIPaddr: string): Boolean;
    procedure CloseSocket(nSocketHandle: Integer);
    function SendUserMsg(UserSession: pTUserSession; sSendMsg: string): Integer;
    procedure ShowMainLogMsg;
    procedure IniUserSessionArray;
    function CloseSocketAndGetIPAddr(nSocketHandle: Integer): string;
    { Private declarations }
  public
    procedure CloseConnect(sIPaddr: string);
    function AddBlockIP(sIPaddr: string): Integer;
    function AddTempBlockIP(sIPaddr: string): Integer;
    procedure MyMessage(var MsgData: TWmCopyData); message WM_COPYDATA;
    { Public declarations }
  end;
procedure MainOutMessage(sMsg: string; nMsgLevel: Integer);
var
  FrmMain: TFrmMain;
  g_SessionArray: TSessionArray;
  ClientSockeMsgList: TStringList;
  sProcMsg: string;
implementation

uses HUtil32, GeneralConfig, IPaddrFilter;

{$R *.DFM}
procedure MainOutMessage(sMsg: string; nMsgLevel: Integer);
var
  tMsg: string;
begin
  try
    CS_MainLog.Enter;
    if nMsgLevel <= nShowLogLevel then begin
      tMsg := '[' + TimeToStr(Now) + '] ' + sMsg;
      MainLogMsgList.Add(tMsg);
    end;
  finally
    CS_MainLog.Leave;
  end;
end;

procedure TFrmMain.ServerSocketClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
  UserSession: pTUserSession;
  sRemoteIPaddr, sLocalIPaddr: string;
  nSockIndex: Integer;
begin
  Socket.nIndex := -1;
  sRemoteIPaddr := Socket.RemoteAddress;

  if IsBlockIP(sRemoteIPaddr) then begin
    Inc(m_nAttackCount);
    m_dwAttackTick := GetTickCount;
    if m_nAttackCount < 10 then begin
      MainOutMessage('过滤连接: ' + sRemoteIPaddr, 1);
    end;
    Socket.Close;
    Exit;
  end;

  if IsConnLimited(sRemoteIPaddr, Socket.SocketHandle) then begin
    if g_boChgDefendLevel then begin
      Inc(m_nAttackCount);
      m_dwAttackTick := GetTickCount;
      if m_nAttackCount >= g_nChgDefendLevel then begin
        if BlockMethod = mDisconnect then BlockMethod := mBlock;
        if nAttackLevel > 1 then nAttackLevel := 1;
      end;
    end;

    case BlockMethod of
      mDisconnect: begin
          Socket.Close;
        end;
      mBlock: begin
          AddTempBlockIP(sRemoteIPaddr);
          CloseConnect(sRemoteIPaddr);
        end;
      mBlockList: begin
          AddBlockIP(sRemoteIPaddr);
          CloseConnect(sRemoteIPaddr);
        end;
    end;
    if m_nAttackCount < 10 then begin
      MainOutMessage('端口攻击: ' + sRemoteIPaddr, 1);
    end;
    Exit;
  end;

  if g_boDynamicIPDisMode then begin
    sLocalIPaddr := ClientSocket.Socket.RemoteAddress;
  end else begin
    sLocalIPaddr := Socket.LocalAddress;
  end;

  if boGateReady then begin
    for nSockIndex := 0 to GATEMAXSESSION - 1 do begin
      UserSession := @g_SessionArray[nSockIndex];
      if UserSession.Socket = nil then begin
        UserSession.Socket := Socket;
        UserSession.sRemoteIPaddr := sRemoteIPaddr;
        UserSession.nSendMsgLen := 0;
        UserSession.nReviceMsgLen := 0;
        UserSession.bo0C := False;
        UserSession.dw10Tick := GetTickCount();
        UserSession.dwConnctCheckTick := GetTickCount();
        UserSession.boSendAvailable := True;
        UserSession.boSendCheck := False;
        UserSession.nCheckSendLength := 0;
        UserSession.n20 := 0;
        UserSession.dwUserTimeOutTick := GetTickCount();
        UserSession.SocketHandle := Socket.SocketHandle;
        UserSession.sIP := sRemoteIPaddr;
        UserSession.dwReceiveTick := GetTickCount();
        UserSession.nReviceMsgLength := 0;
        UserSession.dwReceiveMsgTick := GetTickCount();
        UserSession.MsgList.Clear;
        Socket.nIndex := nSockIndex;
        Inc(nSessionCount);
        break;
      end;
    end;
    if Socket.nIndex >= 0 then begin
      ClientSocket.Socket.SendText('%N' +
        IntToStr(Socket.SocketHandle) +
        '/' +
        sRemoteIPaddr +
        '/' +
        sLocalIPaddr +
        '$');
      MainOutMessage('Connect: ' + sRemoteIPaddr, 5);
    end else begin
      Socket.Close;
      MainOutMessage('Kick Off: ' + sRemoteIPaddr, 1);
    end;
  end else begin
    Socket.Close;
    MainOutMessage('Kick Off: ' + sRemoteIPaddr, 1);
  end;
end;

procedure TFrmMain.ServerSocketClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
  I, II: Integer;
  UserSession: pTUserSession;
  nSockIndex: Integer;
  sRemoteIPaddr: string;
  IPaddr: pTSockaddr;
  nIPaddr: Integer;
  IPList: TList;
begin
  sRemoteIPaddr := Socket.RemoteAddress;
  nSockIndex := Socket.nIndex;
  nIPaddr := inet_addr(PChar(sRemoteIPaddr));
  CurrIPaddrList.Lock;
  try
    for I := CurrIPaddrList.Count - 1 downto 0 do begin
      IPList := TList(CurrIPaddrList.Items[I]);
      if IPList <> nil then begin
        for II := IPList.Count - 1 downto 0 do begin
          IPaddr := IPList.Items[II];
          if (IPaddr.nIPaddr = nIPaddr) and (IPaddr.nSocketHandle = Socket.SocketHandle) then begin
            Dispose(IPaddr);
            IPList.Delete(II);
            if IPList.Count <= 0 then begin
              IPList.Free;
              CurrIPaddrList.Delete(I);
            end;
            break;
          end;
        end;
      end;
    end;
  finally
    CurrIPaddrList.UnLock;
  end;

  if (nSockIndex >= 0) and (nSockIndex < GATEMAXSESSION) then begin
    UserSession := @g_SessionArray[nSockIndex];
    UserSession.Socket := nil;
    UserSession.sRemoteIPaddr := '';
    UserSession.SocketHandle := -1;
    UserSession.MsgList.Clear;
    Dec(nSessionCount);
    if boGateReady then begin
      ClientSocket.Socket.SendText('%C' +
        IntToStr(Socket.SocketHandle) +
        '$');
      MainOutMessage('DisConnect: ' + sRemoteIPaddr, 5);
    end;
  end;
end;

procedure TFrmMain.ServerSocketClientError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
  StringList30C.Add('Error ' + IntToStr(ErrorCode) + ': ' + Socket.RemoteAddress);
  Socket.Close;
  ErrorCode := 0;
end;

procedure TFrmMain.ServerSocketClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  UserSession: pTUserSession;
  nSockIndex: Integer;
  sRemoteAddress, sReviceMsg, s10, s1C: string;
  nPos: Integer;
  nMsgLen: Integer;
  nIPaddr: Integer;
  nMsgCount: Integer;
  bo01: Boolean;
  bo02: Boolean;
begin
  bo01 := False;
  bo02 := False;
  nSockIndex := Socket.nIndex;
  sRemoteAddress := Socket.RemoteAddress;
  if (nSockIndex >= 0) and (nSockIndex < GATEMAXSESSION) then begin
    UserSession := @g_SessionArray[nSockIndex];
    sReviceMsg := Socket.ReceiveText;
    if (sReviceMsg <> '') and (boServerReady) then begin
      nMsgLen := Length(sReviceMsg);
      if nAttackLevel > 0 then begin
        Inc(UserSession.nReviceMsgLen, nMsgLen);
        nMsgCount := TagCount(sReviceMsg, '!');
       { MainOutMessage('nMsgCount: ' + IntToStr(nMsgCount), 1);
        MainOutMessage('nMsgLen: ' + IntToStr(nMsgLen), 1); }
        if nMsgCount > nMaxClientMsgCount * nAttackLevel then bo02 := True;
        if nMsgLen > 352{ * nAttackLevel} then bo01 := True;
        if bo01 or bo02 then begin

          if g_boChgDefendLevel then begin
            Inc(m_nAttackCount);
            m_dwAttackTick := GetTickCount;
            if m_nAttackCount >= g_nChgDefendLevel then begin
              if BlockMethod = mDisconnect then BlockMethod := mBlock;
              if nAttackLevel > 1 then nAttackLevel := 1;
            end;
          end;

          case BlockMethod of
            mDisconnect: begin
                //Socket.Close;
              end;
            mBlock: begin
                AddTempBlockIP(sRemoteAddress);
                CloseConnect(sRemoteAddress);
              end;
            mBlockList: begin
                AddBlockIP(sRemoteAddress);
                CloseConnect(sRemoteAddress);
              end;
          end;
          if m_nAttackCount < 10 then begin
            if bo01 then
              MainOutMessage('端口攻击: ' + sRemoteAddress + ' 数据包长度: ' + IntToStr(UserSession.nReviceMsgLen), 1);
            if bo02 then
              MainOutMessage('端口攻击: ' + sRemoteAddress + ' 信息数量:' + IntToStr(nMsgCount), 1);
          end;
          Socket.Close;
          Exit;
        end;
      end;

      nPos := Pos('*', sReviceMsg);
      if nPos > 0 then begin
        UserSession.boSendAvailable := True;
        UserSession.boSendCheck := False;
        UserSession.nCheckSendLength := 0;
        UserSession.dwReceiveTick := GetTickCount();
        s10 := Copy(sReviceMsg, 1, nPos - 1);
        s1C := Copy(sReviceMsg, nPos + 1, Length(sReviceMsg) - nPos);
        sReviceMsg := s10 + s1C;
      end;
      nMsgLen := Length(sReviceMsg);

      if UserSession.nReviceMsgLength <= 0 then
        UserSession.dwReceiveMsgTick := GetTickCount();
      Inc(UserSession.nReviceMsgLength, nMsgLen);

      if (sReviceMsg <> '') and (boGateReady) and (not boKeepAliveTimcOut) then begin
        UserSession.dwConnctCheckTick := GetTickCount();
        if (GetTickCount - UserSession.dwUserTimeOutTick) < 1000 then begin
          Inc(UserSession.n20, nMsgLen);
        end else UserSession.n20 := nMsgLen;
        ClientSocket.Socket.SendText('%D' +
          IntToStr(Socket.SocketHandle) +
          '/' +
          sReviceMsg +
          '$');
      end;
    end;
  end;
end;

procedure TFrmMain.MemoLogChange(Sender: TObject);
begin
  if MemoLog.Lines.Count > 200 then MemoLog.Clear;
end;

procedure TFrmMain.FormDestroy(Sender: TObject);
var
  nIndex: Integer;
begin
  StringList30C.Free;
  TempLogList.Free;
  for nIndex := 0 to GATEMAXSESSION - 1 do begin
    g_SessionArray[nIndex].MsgList.Free;
  end;
end;

procedure TFrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if boClose then Exit;
  if Application.MessageBox('是否确认退出服务器?',
    '提示信息',
    MB_YESNO + MB_ICONQUESTION) = IDYES then begin
    if boServiceStart then begin
      StartTimer.Enabled := True;
      CanClose := False;
    end;
  end else CanClose := False;
end;

procedure TFrmMain.ClientSocketConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  boGateReady := True;
  nSessionCount := 0;
  dwKeepAliveTick := GetTickCount();
  ResUserSessionArray();
  boServerReady := True;
end;

procedure TFrmMain.ClientSocketDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
  UserSession: pTUserSession;
  nIndex: Integer;
begin
  for nIndex := 0 to GATEMAXSESSION - 1 do begin
    UserSession := @g_SessionArray[nIndex];
    if UserSession.Socket <> nil then
      UserSession.Socket.Close;
    UserSession.Socket := nil;
    UserSession.sRemoteIPaddr := '';
    UserSession.SocketHandle := -1;
  end;
  ResUserSessionArray();
  ClientSockeMsgList.Clear;
  boGateReady := False;
  nSessionCount := 0;
end;

procedure TFrmMain.ClientSocketError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
  Socket.Close;
  ErrorCode := 0;
  boServerReady := False;
end;

procedure TFrmMain.ClientSocketRead(Sender: TObject;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?