Subversion Repositories qbpwcf-lib(archive)

Rev

Rev 556 | Rev 565 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#!/usr/bin/php
<?php

/*
        QBPWCF, Quick Build PHP website Component base on Fedora Linux.
    Copyright (C) 2015~2023 Min-Jhin,Chen

    This file is part of QBPWCF.

    QBPWCF is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    QBPWCF is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with QBPWCF.  If not, see <http://www.gnu.org/licenses/>.
    
*/

/*
封鎖來自http、https、smtp、named的惡意ip. 
*/

/*

bug log:

journalctl -a | grep ipBlockerd.php
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]: 內建白名單:169.254.1.1
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]: 附加白名單:169.254.1.1
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]: array(2) {
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:   ["status"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:   string(5) "false"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:   ["error"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:   array(4) {
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:     ["function"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:     string(8) "fileInfo"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:     ["argu"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:     array(3) {
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       ["fileArgu"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       string(47) "/usr/lib/20230429/qbpwcf/usr/bin/ipBlockerd.php"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       ["file"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       string(25) "/var/log/httpd/access_log"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       ["web"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       string(5) "false"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:     }
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:     ["status"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:     string(5) "false"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:     ["error"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:     array(7) {
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       ["function"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       string(19) "checkMultiFileExist"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       ["argu"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       array(3) {
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         ["fileArray"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         array(1) {
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:           [0]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:           string(25) "/var/log/httpd/access_log"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         }
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         ["fileArgu"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         string(47) "/usr/lib/20230429/qbpwcf/usr/bin/ipBlockerd.php"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         ["web"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         string(5) "false"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       }
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       ["varName"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       array(1) {
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         [0]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         string(25) "/var/log/httpd/access_log"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       }
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       ["varExist"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       array(1) {
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         [0]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         string(5) "false"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       }
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       ["varNameFullPath"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       array(1) {
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         [0]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:         string(25) "/var/log/httpd/access_log"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       }
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       ["allExist"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       string(5) "false"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       ["status"]=>
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:       string(4) "true"
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:     }
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]:   }
Apr 29 20:03:38 ip-172-31-33-199.ap-northeast-1.compute.internal ipBlockerd.php[2362579]: }

*/

#指派命名空間
namespace qbpwcf;

#以該檔案的實際位置的 lib path 為 include path 首位
exec("cd ".pathinfo(__FILE__)["dirname"]."/../../;pwd;",$output,$status);
set_include_path($output[0].PATH_SEPARATOR.get_include_path());

#匯入外部套件
include("allInOne.php");

#初始化記錄 http log 最後變更的時間
$preHttpTimeFloat=0;

#初始化記錄 https log 最後變更的時間
$preHttpsTimeFloat=0;

#初始化記錄 smtpd log 最後變更的時間
$preSmtpTimeFloat=0;

#初始化記錄 dovecot/imap log 最後變更的時間
$preImapTimeFloat=0;

#初始化記錄 named log 最後變更的時間
$preNamedTimeFloat=0;

#初始化不啟用debug模式
$debug=false;

#取得參數
/*
#函式說明:
#解析參數.
#回傳結果:
#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.
#$reuslt["error"],執行不正常結束的錯訊息陣列.
#$result["function"],當前執行的函式名稱.
#$result["content"],解析好的參數陣列.
#$result["content"][$key][$i],參數 $key 的 $i+1 個參數數值內容.
#$result["program"],字串,執行的程式名稱.
#必填參數:
#無
#可省略參數:
#無
#備註:
#僅能在命令列底下執行.
#建議:
#以後可將參數 --a--b 的名稱與後面的數值 $value 存成 $result["a"]["b"][$i]=$value .
*/
$conf=array();
$parseArgu=cmd::parseArgu($conf);
unset($conf);

#如果有debug參數
if(isset($parseArgu["content"]["debug"])){

        #如果第一個參數為 "--debug true"
        if($parseArgu["content"]["debug"][0]==="true"){

                #設置debug模式
                $debug=true;

                #comment
                echo "debug mode".PHP_EOL;

                }#if end        

        }#if end
        
#取得自己對外的ip
#函式說明:
#依據提供查詢IP服務的網站取得伺服器對外的IP.
#回傳結果:
#$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.
#$result["function"],當前執行的函數名稱.
#$result["error"],錯誤訊息陣列.
#$result["content"],伺服端對外的IP.
#必填參數:
#$conf["fileArgu"],字串,php變數__FILE__的內容,亦即該檔案在檔案系統的絕對路徑
$conf["fileArgu"]=__FILE__;
#可省略參數:
#無.
#備註:
#需要有網站支援此服務.
$getServerRealIP=csInformation::getServerRealIP($conf);
unset($conf);   

#如果執行失敗
if($getServerRealIP["status"]==="false"){

        #設置執行失敗
        $result["status"]="false";

        #設置錯誤訊息
        $result["error"]=$getServerRealIP;

        #印出結果
        var_dump($result);
        
        #結束執行
        exit;

        }#if end

#預設的白名單為自己對外的IP
$excludeIp=array($getServerRealIP["content"][0]);       

#提示內建白名單
echo "內建白名單:".$excludeIp[0].PHP_EOL;
        
#如果有 exclude 參數
if(isset($parseArgu["content"]["exclude"])){

        #針對每個白名單 IP
        foreach($parseArgu["content"]["exclude"] as $whiteIp){
                
                #提示內建白名單
                echo "附加白名單:".$whiteIp.PHP_EOL;
                
                #取得每個指定要排除的ip
                $excludeIp[]=$whiteIp;
        
                }#foreach end
        
        }#if end

#永久執行
while(true){

        #debug mode
        if($debug){

                #comment
                echo "while loop".PHP_EOL;
                
                }#if end

        #函數說明:
        #依據取得檔案的擁有着資訊
        #回傳結果:
        #$result["status"],"true"爲建立成功,"false"爲建立失敗.
        #$result["error"],錯誤訊息陣列.
        #$result["function"],函數名稱. 
        #$result["content"],檔案資訊陣列.
        #$result["content"]["is_folder"],是否為目錄,"true"代表是,"false"代表不是.   
        #$result["content"]["ownerPerm"],檔案擁有者權限資訊.
        #$result["content"]["groupPerm"],檔案歸屬群組權限資訊.
        #$result["content"]["otherPerm"],檔案對於其他身份使用者的權限資訊.
        #$result["content"]["subElementCount"],目錄底下的檔案目錄數量.
        #$result["content"]["ownerName"],檔案擁有着資訊.
        #$result["content"]["groupName"],檔案所屬擁有着資訊.
        #$result["content"]["size"],檔案大小.
        #$result["content"]["modifyDate"],檔案變更年月日.
        #$result["content"]["modifyTime"],檔案變更時分秒.
        #$result["content"]["modifyTimeFloat"],檔案變更時間秒的float數值.
        #$result["content"]["timezone"],檔案變更時間的時區與UTC的差距.
        #必填參數:
        #$conf["fileArgu"],字串,當前檔案的位置亦即__FILE__的內容.
        $conf["fileArgu"]=__FILE__;
        #$conf["file"],字串,要查看擁有者資訊的檔案.
        $conf["file"]="/var/log/httpd/access_log";
        $conf["web"]="false";
        #參考資料:
        #fileowner=>http://php.net/manual/en/function.fileowner.php
        #posix_getpwuid=>http://php.net/manual/en/function.posix-getpwuid.php
        $httpFileInfo=fileAccess::fileInfo($conf);
        unset($conf);
        
        #如果運行失敗
        if($httpFileInfo["status"]==="false"){
        
                #設置執行失敗
                $result["status"]="false";

                #設置錯誤訊息
                $result["error"]=$httpFileInfo;

                #印出結果
                var_dump($result);
                
                #結束執行
                exit;
        
                }#if end
                
        #debug
        if($debug){
                
                #comment
                echo "accessed file /var/log/httpd/access_log".PHP_EOL;
                
                }#if end
                
        #記錄 http log 的最後變更時間
        $httpTimeFloat=$httpFileInfo["content"]["modifyTimeFloat"];
        
        #函數說明:
        #依據取得檔案的擁有着資訊
        #回傳結果:
        #$result["status"],"true"爲建立成功,"false"爲建立失敗.
        #$result["error"],錯誤訊息陣列.
        #$result["function"],函數名稱. 
        #$result["content"],檔案資訊陣列.
        #$result["content"]["is_folder"],是否為目錄,"true"代表是,"false"代表不是.   
        #$result["content"]["ownerPerm"],檔案擁有者權限資訊.
        #$result["content"]["groupPerm"],檔案歸屬群組權限資訊.
        #$result["content"]["otherPerm"],檔案對於其他身份使用者的權限資訊.
        #$result["content"]["subElementCount"],目錄底下的檔案目錄數量.
        #$result["content"]["ownerName"],檔案擁有着資訊.
        #$result["content"]["groupName"],檔案所屬擁有着資訊.
        #$result["content"]["size"],檔案大小.
        #$result["content"]["modifyDate"],檔案變更年月日.
        #$result["content"]["modifyTime"],檔案變更時分秒.
        #$result["content"]["modifyTimeFloat"],檔案變更時間秒的float數值.
        #$result["content"]["timezone"],檔案變更時間的時區與UTC的差距.
        #必填參數:
        #$conf["fileArgu"],字串,當前檔案的位置亦即__FILE__的內容.
        $conf["fileArgu"]=__FILE__;
        #$conf["file"],字串,要查看擁有者資訊的檔案.
        $conf["file"]="/var/log/httpd/ssl_access_log";
        $conf["web"]="false";
        #參考資料:
        #fileowner=>http://php.net/manual/en/function.fileowner.php
        #posix_getpwuid=>http://php.net/manual/en/function.posix-getpwuid.php
        $httpsFileInfo=fileAccess::fileInfo($conf);
        unset($conf);

        #如果運行失敗
        if($httpsFileInfo["status"]==="false"){
        
                #設置執行失敗
                $result["status"]="false";

                #設置錯誤訊息
                $result["error"]=$httpsFileInfo;

                #印出結果
                var_dump($result);
                
                #結束執行
                exit;
        
                }#if end

        #debug
        if($debug){
                
                #comment
                echo "accessed file /var/log/httpd/ssl_access_log".PHP_EOL;
                
                }#if end

        #記錄 https log 的最後變更時間
        $httpsTimeFloat=$httpsFileInfo["content"]["modifyTimeFloat"];

        #透過運行以下指令取得最後變更時間
        #journalctl -a -e | grep postfix/smtpd | grep " connect from unknown" | tail -n 1
        #涵式說明:
        #呼叫shell執行系統命令,並取得回傳的內容.
        #回傳的結果:
        #$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.
        #$result["error"],錯誤訊息陣列.
        #$result["function"],當前執行的函數名稱.
        #$result["argu"],使用的參數.
        #$result["cmd"],執行的指令內容.
        #$result["fullCmd"],如果參數 $conf["inBackGround"] 為 "true" 則會回傳該值.
        #$result["output"],爲執行完二元碼後的輸出陣列,若 $conf["inBackGround"] 為 "true",則為當下的輸出.
        #$result["tmpFileOutput"],儲存輸出的暫存檔案名稱,若 $conf["inBackGround"] 為 "true" 則會回傳該值.
        #$result["running"],是否還在執行.
        #$result["pid"],pid.
        #$result["statusCode"],執行結束後的代碼.
        #必填的參數
        #$conf["command"],字串,要執行的指令與.
        $conf["external::callShell"]["command"]="journalctl";
        #$conf["fileArgu"],字串,變數__FILE__的內容.
        $conf["external::callShell"]["fileArgu"]=__FILE__;              
        #可省略參數:
        #$conf["argu"],陣列字串,指令搭配的參數,預設為空陣列.
        $conf["external::callShell"]["argu"]=array("-a","-e","|","grep","postfix/smtps/smtpd","|","grep"," connect from unknown","|","tail","-n","1");
        #$conf["arguIsAddr"],陣列字串,指令搭配的哪些參數為路徑,為路徑的參數會進行轉換以便符合呼叫當前函數的位置,預設不指定,若有3個參數,其中第3個參數為路徑,則表示為array("false","false","true").
        #$conf["arguIsAddr"]=array();   
        #$conf["pre"],陣列,要在本指令前執行的每個指令與參數.
        #$conf["pre"][$i]["cmd"],字串,要在本指令前執行的第$i+1個指令.
        #$conf["pre"][$i]["param"],陣列字串,要在本指令前執行的第$i+1個指令的參數.
        #$conf["enablePrintDescription"],字串,是否要印出$conf["printDescription"]的內容,"true"代表要,"false"代表不要,預設為"false".
        #$conf["enablePrintDescription"]="true";
        #$conf["printDescription"],字串,執行該外部程式前要印出來的的文字,預設為$conf["command"]的內容加上使用的$conf["argu"]參數.
        #$conf["printDescription"]="";
        #$conf["escapeshellarg"],字串,是否要啟用過濾參數,用了比較安全,但可能會出錯,"true"為啟用,"false"為不啟用,預設為"false".
        $conf["external::callShell"]["escapeshellarg"]="true";
        #$conf["username"],字串,要用什麼使用者來執行,預設為執行php的使用者,該參數不適用於apache環境.
        #$conf["username"]="";
        #$conf["password"],字串,root的使用者密碼,預設不使用密碼,該參數不適用於apache環境.
        #$conf["password"]="";
        #$conf["useScript"],字串,是否要啟用Linux的script指令來記錄輸出,"true"代表要,Fedora的selinux會擋住該操作;"false"代表不要,預設為"false".
        #$conf["useScript"]="";
        #$conf["logFilePath"],字串,當 $conf["useScript"] 為 "true" 時,輸出的內容要暫存到哪裡,預設為 "/tmp/.qbpwcf_tmp/external/callShell/".
        #$conf["logFilePath"]=".qbpwcf_tmp/external/callShell/";
        #$conf["inBackGround"],字串,是否要在背景執行,且不會等待程式執行結束再執行下一個指令,"true"代表是,"false"代表不要,預設為"false",如果$conf["command"]有用「;」區隔的多個指令將會出錯.
        #$conf["inBackGround"]="";
        #$conf["getErr"],字串,"true"代表將錯誤輸出變成標準輸出,反之"false"為不變動.
        #$conf["getErr"]="false";
        #備註:
        #不是所有指令都能用apache的身份執行,目前已知java,javac指令無法執行,使用root身份可能會被selinux阻擋.
        #參考資料:
        #exec=>http://php.net/manual/en/function.exec.php
        #escapeshellcmd=>http://php.net/manual/en/function.escapeshellcmd.php
        #escapeshellarg=>http://php.net/manual/en/function.escapeshellarg.php
        $callShell=external::callShell($conf["external::callShell"]);
        unset($conf["external::callShell"]);
        
        #如果執行失敗
        if($callShell["status"]==="false"){
        
                #設置執行失敗
                $result["status"]="false";

                #設置錯誤訊息
                $result["error"]=$callShell;

                #回傳結果
                var_dump($result);
                
                #結束執行
                exit;
                
                }#if end
        
        #debug
        if($debug){
                
                #comment
                echo "accessed file postfix/smtp log".PHP_EOL;
                
                }#if end
        
        #取得行數
        $lineCount=count($callShell["output"]);
        
        #如果行數等於1
        if($lineCount===1){
        
                #debug
                if($debug){
                        
                        #最新一筆惡意IP
                        #echo "最新一筆惡意IP:".PHP_EOL;
                        #var_dump($callShell["output"]);
                        
                        }#if end
                
                #Aug 09 07:12:09 www.qbpwcf.org postfix/smtpd[20829]: connect from unknown[185.234.219.62]
                #Apr 04 15:11:16 mail.qbpwcf.org postfix/smtps/smtpd[10145]: connect from unknown[212.70.149.72]
                $unProcesedStr=$callShell["output"];
                
                #分割字串
                #涵式說明:
                #將多個固定格式的字串分開,並回傳分開的結果
                #回傳的參數:
                #$result["status"],執行成功與否,若爲"true",代表執行成功,若爲"false"代表執失敗。
                #$result["error"],錯誤訊息陣列.
                #$result["function"],當前執行的函數名稱.
                #$result["spiltString"][$i]["oriStr"],爲第i個字串的原始內容
                #$result["spiltString"][$i]["dataArray"],爲第($i+1)個字串分割後的字串陣列
                #$result["spiltString"][$i]["dataArray"][$j],爲第($i+1)的分割好的字串的第($j+1)段內容
                #$result["spiltString"][$i]["dataCounts"],爲第($i+1)個字串分割後總共分成幾段
                #必填的參數:
                #$conf["stringIn"],字串陣列,要處理的字串陣列.
                $conf["stringProcess::spiltMutiString"]["stringIn"]=$unProcesedStr;
                #$conf["spiltSymbol"],字串,爲要以哪個符號作爲分割.
                $conf["stringProcess::spiltMutiString"]["spiltSymbol"]=" ";
                $spiltMutiString=stringProcess::spiltMutiString($conf["stringProcess::spiltMutiString"]);
                unset($conf["stringProcess::spiltMutiString"]);
                
                #如果分割失敗
                if($spiltMutiString["status"]==="false"){
                
                        #設置執行失敗
                        $result["status"]="false";

                        #設置錯誤訊息
                        $result["error"]=$spiltMutiString;

                        #印出結果
                        var_dump($result);
                        
                        #停止執行
                        exit;
                        
                        }#if end
                        
                #記錄 smtpd log 最後變更的時間
                $smtpTimeFloat=$spiltMutiString["spiltString"][0]["dataArray"][2];
                
                }#if end
        
        #反之
        else{
        
                #記錄 smtpd log 最後變更的時間爲0
                $smtpTimeFloat=0;

                }#else end
                
        #透過運行以下指令取得最後變更時間
        #journalctl -a -e | grep dovecot | grep " failed" | tail -n 1
        #涵式說明:
        #呼叫shell執行系統命令,並取得回傳的內容.
        #回傳的結果:
        #$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.
        #$result["error"],錯誤訊息陣列.
        #$result["function"],當前執行的函數名稱.
        #$result["argu"],使用的參數.
        #$result["cmd"],執行的指令內容.
        #$result["fullCmd"],如果參數 $conf["inBackGround"] 為 "true" 則會回傳該值.
        #$result["output"],爲執行完二元碼後的輸出陣列,若 $conf["inBackGround"] 為 "true",則為當下的輸出.
        #$result["tmpFileOutput"],儲存輸出的暫存檔案名稱,若 $conf["inBackGround"] 為 "true" 則會回傳該值.
        #$result["running"],是否還在執行.
        #$result["pid"],pid.
        #$result["statusCode"],執行結束後的代碼.
        #必填的參數
        #$conf["command"],字串,要執行的指令與.
        $conf["external::callShell"]["command"]="journalctl";
        #$conf["fileArgu"],字串,變數__FILE__的內容.
        $conf["external::callShell"]["fileArgu"]=__FILE__;              
        #可省略參數:
        #$conf["argu"],陣列字串,指令搭配的參數,預設為空陣列.
        $conf["external::callShell"]["argu"]=array("-a","-e","|","grep","dovecot","|","grep"," failed","|","tail","-n","1");
        #$conf["arguIsAddr"],陣列字串,指令搭配的哪些參數為路徑,為路徑的參數會進行轉換以便符合呼叫當前函數的位置,預設不指定,若有3個參數,其中第3個參數為路徑,則表示為array("false","false","true").
        #$conf["arguIsAddr"]=array();   
        #$conf["pre"],陣列,要在本指令前執行的每個指令與參數.
        #$conf["pre"][$i]["cmd"],字串,要在本指令前執行的第$i+1個指令.
        #$conf["pre"][$i]["param"],陣列字串,要在本指令前執行的第$i+1個指令的參數.
        #$conf["enablePrintDescription"],字串,是否要印出$conf["printDescription"]的內容,"true"代表要,"false"代表不要,預設為"false".
        #$conf["enablePrintDescription"]="true";
        #$conf["printDescription"],字串,執行該外部程式前要印出來的的文字,預設為$conf["command"]的內容加上使用的$conf["argu"]參數.
        #$conf["printDescription"]="";
        #$conf["escapeshellarg"],字串,是否要啟用過濾參數,用了比較安全,但可能會出錯,"true"為啟用,"false"為不啟用,預設為"false".
        $conf["external::callShell"]["escapeshellarg"]="true";
        #$conf["username"],字串,要用什麼使用者來執行,預設為執行php的使用者,該參數不適用於apache環境.
        #$conf["username"]="";
        #$conf["password"],字串,root的使用者密碼,預設不使用密碼,該參數不適用於apache環境.
        #$conf["password"]="";
        #$conf["useScript"],字串,是否要啟用Linux的script指令來記錄輸出,"true"代表要,Fedora的selinux會擋住該操作;"false"代表不要,預設為"false".
        #$conf["useScript"]="";
        #$conf["logFilePath"],字串,當 $conf["useScript"] 為 "true" 時,輸出的內容要暫存到哪裡,預設為 "/tmp/.qbpwcf_tmp/external/callShell/".
        #$conf["logFilePath"]=".qbpwcf_tmp/external/callShell/";
        #$conf["inBackGround"],字串,是否要在背景執行,且不會等待程式執行結束再執行下一個指令,"true"代表是,"false"代表不要,預設為"false",如果$conf["command"]有用「;」區隔的多個指令將會出錯.
        #$conf["inBackGround"]="";
        #$conf["getErr"],字串,"true"代表將錯誤輸出變成標準輸出,反之"false"為不變動.
        #$conf["getErr"]="false";
        #備註:
        #不是所有指令都能用apache的身份執行,目前已知java,javac指令無法執行,使用root身份可能會被selinux阻擋.
        #參考資料:
        #exec=>http://php.net/manual/en/function.exec.php
        #escapeshellcmd=>http://php.net/manual/en/function.escapeshellcmd.php
        #escapeshellarg=>http://php.net/manual/en/function.escapeshellarg.php
        $callShell=external::callShell($conf["external::callShell"]);
        unset($conf["external::callShell"]);
        
        #如果執行失敗
        if($callShell["status"]==="false"){
        
                #設置執行失敗
                $result["status"]="false";

                #設置錯誤訊息
                $result["error"]=$callShell;

                #回傳結果
                var_dump($result);
                
                #結束執行
                exit;
                
                }#if end
        
        #debug
        if($debug){
                
                #comment
                echo "accessed file dovecot/imap log".PHP_EOL;
                
                }#if end
        
        #取得行數
        $lineCount=count($callShell["output"]);
        
        #如果行數等於1
        if($lineCount===1){
        
                #debug
                if($debug){
                        
                        #最新一筆惡意IP
                        #echo "最新一筆惡意IP:".PHP_EOL;
                        #var_dump($callShell["output"]);
                        
                        }#if end
                
                #Feb 23 07:44:29 localhost.localdomain dovecot[1427]: imap-login: Disconnected (no auth attempts in 0 secs): user=<>, rip=101.136.215.61, lip=169.254.1.1, TLS handshaking: SSL_accept() failed: error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown: SSL alert number 46, session=<9oMMYvW7ihhliNc9>
                $unProcesedStr=$callShell["output"];
                
                #分割字串
                #涵式說明:
                #將多個固定格式的字串分開,並回傳分開的結果
                #回傳的參數:
                #$result["status"],執行成功與否,若爲"true",代表執行成功,若爲"false"代表執失敗。
                #$result["error"],錯誤訊息陣列.
                #$result["function"],當前執行的函數名稱.
                #$result["spiltString"][$i]["oriStr"],爲第i個字串的原始內容
                #$result["spiltString"][$i]["dataArray"],爲第($i+1)個字串分割後的字串陣列
                #$result["spiltString"][$i]["dataArray"][$j],爲第($i+1)的分割好的字串的第($j+1)段內容
                #$result["spiltString"][$i]["dataCounts"],爲第($i+1)個字串分割後總共分成幾段
                #必填的參數:
                #$conf["stringIn"],字串陣列,要處理的字串陣列.
                $conf["stringProcess::spiltMutiString"]["stringIn"]=$unProcesedStr;
                #$conf["spiltSymbol"],字串,爲要以哪個符號作爲分割.
                $conf["stringProcess::spiltMutiString"]["spiltSymbol"]=" ";
                $spiltMutiString=stringProcess::spiltMutiString($conf["stringProcess::spiltMutiString"]);
                unset($conf["stringProcess::spiltMutiString"]);
                
                #如果分割失敗
                if($spiltMutiString["status"]==="false"){
                
                        #設置執行失敗
                        $result["status"]="false";

                        #設置錯誤訊息
                        $result["error"]=$spiltMutiString;

                        #印出結果
                        var_dump($result);
                        
                        #停止執行
                        exit;
                        
                        }#if end
                        
                #記錄 smtpd log 最後變更的時間
                $imapTimeFloat=$spiltMutiString["spiltString"][0]["dataArray"][2];
                
                }#if end
        
        #反之
        else{
        
                #記錄 imap log 最後變更的時間爲0
                $imapTimeFloat=0;

                }#else end

        #透過 journalctl -a -e | grep named | tail -n 1 來取得最後一筆 dns 查詢記錄        
        #涵式說明:
        #呼叫shell執行系統命令,並取得回傳的內容.
        #回傳的結果:
        #$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.
        #$result["error"],錯誤訊息陣列.
        #$result["function"],當前執行的函數名稱.
        #$result["argu"],使用的參數.
        #$result["cmd"],執行的指令內容.
        #$result["fullCmd"],如果參數 $conf["inBackGround"] 為 "true" 則會回傳該值.
        #$result["output"],爲執行完二元碼後的輸出陣列,若 $conf["inBackGround"] 為 "true",則為當下的輸出.
        #$result["tmpFileOutput"],儲存輸出的暫存檔案名稱,若 $conf["inBackGround"] 為 "true" 則會回傳該值.
        #$result["running"],是否還在執行.
        #$result["pid"],pid.
        #$result["statusCode"],執行結束後的代碼.
        #必填的參數
        #$conf["command"],字串,要執行的指令與.
        $conf["external::callShell"]["command"]="journalctl";
        #$conf["fileArgu"],字串,變數__FILE__的內容.
        $conf["external::callShell"]["fileArgu"]=__FILE__;              
        #可省略參數:
        #$conf["argu"],陣列字串,指令搭配的參數,預設為空陣列.
        $conf["external::callShell"]["argu"]=array("-a","-e","|","grep"," named","|","tail","-n","1");
        #$conf["arguIsAddr"],陣列字串,指令搭配的哪些參數為路徑,為路徑的參數會進行轉換以便符合呼叫當前函數的位置,預設不指定,若有3個參數,其中第3個參數為路徑,則表示為array("false","false","true").
        #$conf["arguIsAddr"]=array();   
        #$conf["pre"],陣列,要在本指令前執行的每個指令與參數.
        #$conf["pre"][$i]["cmd"],字串,要在本指令前執行的第$i+1個指令.
        #$conf["pre"][$i]["param"],陣列字串,要在本指令前執行的第$i+1個指令的參數.
        #$conf["enablePrintDescription"],字串,是否要印出$conf["printDescription"]的內容,"true"代表要,"false"代表不要,預設為"false".
        #$conf["enablePrintDescription"]="true";
        #$conf["printDescription"],字串,執行該外部程式前要印出來的的文字,預設為$conf["command"]的內容加上使用的$conf["argu"]參數.
        #$conf["printDescription"]="";
        #$conf["escapeshellarg"],字串,是否要啟用過濾參數,用了比較安全,但可能會出錯,"true"為啟用,"false"為不啟用,預設為"false".
        $conf["external::callShell"]["escapeshellarg"]="true";
        #$conf["username"],字串,要用什麼使用者來執行,預設為執行php的使用者,該參數不適用於apache環境.
        #$conf["username"]="";
        #$conf["password"],字串,root的使用者密碼,預設不使用密碼,該參數不適用於apache環境.
        #$conf["password"]="";
        #$conf["useScript"],字串,是否要啟用Linux的script指令來記錄輸出,"true"代表要,Fedora的selinux會擋住該操作;"false"代表不要,預設為"false".
        #$conf["useScript"]="";
        #$conf["logFilePath"],字串,當 $conf["useScript"] 為 "true" 時,輸出的內容要暫存到哪裡,預設為 "/tmp/.qbpwcf_tmp/external/callShell/".
        #$conf["logFilePath"]=".qbpwcf_tmp/external/callShell/";
        #$conf["inBackGround"],字串,是否要在背景執行,且不會等待程式執行結束再執行下一個指令,"true"代表是,"false"代表不要,預設為"false",如果$conf["command"]有用「;」區隔的多個指令將會出錯.
        #$conf["inBackGround"]="";
        #$conf["getErr"],字串,"true"代表將錯誤輸出變成標準輸出,反之"false"為不變動.
        #$conf["getErr"]="false";
        #備註:
        #不是所有指令都能用apache的身份執行,目前已知java,javac指令無法執行,使用root身份可能會被selinux阻擋.
        #參考資料:
        #exec=>http://php.net/manual/en/function.exec.php
        #escapeshellcmd=>http://php.net/manual/en/function.escapeshellcmd.php
        #escapeshellarg=>http://php.net/manual/en/function.escapeshellarg.php
        $callShell=external::callShell($conf["external::callShell"]);
        unset($conf["external::callShell"]);
        
        #如果執行失敗
        if($callShell["status"]==="false"){
        
                #設置執行失敗
                $result["status"]="false";

                #設置錯誤訊息
                $result["error"]=$callShell;

                #回傳結果
                var_dump($result);
                
                #結束執行
                exit;
                
                }#if end
        
        #debug
        if($debug){
                
                #comment
                echo "accessed file named log".PHP_EOL;
                
                }#if end
        
        #取得行數
        $lineCount=count($callShell["output"]);
        
        #如果行數等於1
        if($lineCount===1){
        
                #debug
                if($debug){
                        
                        #最新一筆惡意IP
                        #echo "最新一筆惡意IP:".PHP_EOL;
                        #var_dump($callShell["output"]);
                        
                        }#if end
                
                #Aug 09 07:12:09 www.qbpwcf.org postfix/smtpd[20829]: connect from unknown[185.234.219.62]
                $unProcesedStr=$callShell["output"];
                
                #分割字串
                #涵式說明:
                #將多個固定格式的字串分開,並回傳分開的結果
                #回傳的參數:
                #$result["status"],執行成功與否,若爲"true",代表執行成功,若爲"false"代表執失敗。
                #$result["error"],錯誤訊息陣列.
                #$result["function"],當前執行的函數名稱.
                #$result["spiltString"][$i]["oriStr"],爲第i個字串的原始內容
                #$result["spiltString"][$i]["dataArray"],爲第($i+1)個字串分割後的字串陣列
                #$result["spiltString"][$i]["dataArray"][$j],爲第($i+1)的分割好的字串的第($j+1)段內容
                #$result["spiltString"][$i]["dataCounts"],爲第($i+1)個字串分割後總共分成幾段
                #必填的參數:
                #$conf["stringIn"],字串陣列,要處理的字串陣列.
                $conf["stringProcess::spiltMutiString"]["stringIn"]=$unProcesedStr;
                #$conf["spiltSymbol"],字串,爲要以哪個符號作爲分割.
                $conf["stringProcess::spiltMutiString"]["spiltSymbol"]=" ";
                $spiltMutiString=stringProcess::spiltMutiString($conf["stringProcess::spiltMutiString"]);
                unset($conf["stringProcess::spiltMutiString"]);
                
                #如果分割失敗
                if($spiltMutiString["status"]==="false"){
                
                        #設置執行失敗
                        $result["status"]="false";

                        #設置錯誤訊息
                        $result["error"]=$spiltMutiString;

                        #印出結果
                        var_dump($result);
                        
                        #停止執行
                        exit;
                        
                        }#if end
                        
                #記錄 named log 最後變更的時間
                $namedTimeFloat=$spiltMutiString["spiltString"][0]["dataArray"][2];
                
                }#if end
        
        #反之
        else{
        
                #記錄 named log 最後變更的時間爲0
                $namedTimeFloat=0;

                }#else end

        #debug mode
        if($debug){

                #comment
                echo "\$preHttpTimeFloat:".$preHttpTimeFloat.PHP_EOL;
                echo "\$preHttpsTimeFloat:".$preHttpsTimeFloat.PHP_EOL;
                echo "\$preSmtpTimeFloat:".$preSmtpTimeFloat.PHP_EOL;
                echo "\$preImapTimeFloat:".$preImapTimeFloat.PHP_EOL;
                echo "\$preNamedTimeFloat:".$preNamedTimeFloat.PHP_EOL;
                echo "\$httpTimeFloat:".$httpTimeFloat.PHP_EOL;
                echo "\$httpsTimeFloat:".$httpsTimeFloat.PHP_EOL;
                echo "\$smtpTimeFloat:".$smtpTimeFloat.PHP_EOL;
                echo "\$imapTimeFloat:".$imapTimeFloat.PHP_EOL;
                echo "\$namedTimeFloat:".$namedTimeFloat.PHP_EOL;

                }#if end

        #第一次運行,不做事.
        if($preHttpTimeFloat===0 && $preHttpsTimeFloat===0 && $preSmtpTimeFloat===0 && $preImapTimeFloat===0 && $preNamedTimeFloat===0){

                #將本次http記錄覆寫到上次的記錄
                $preHttpTimeFloat=$httpTimeFloat;
                
                #將本次https記錄覆寫到上次的記錄
                $preHttpsTimeFloat=$httpsTimeFloat;
                
                #將本次smtps記錄覆寫到上次的記錄
                $preSmtpTimeFloat=$smtpTimeFloat;
                
                #將本次imaps記錄覆寫到上次的記錄
                $preImapTimeFloat=$imapTimeFloat;
                
                #將本次nmaed記錄覆寫到上次的記錄
                $preNamedTimeFloat=$namedTimeFloat;
                
                #睡一秒
                sleep(1);

                #debug mode
                if($debug){

                        #comment
                        echo "第一次運行,不做事".PHP_EOL;

                        }#if end

                #下一輪
                continue;
        
                }#if end
                
        #非第一次運行,且 http 與 https log 都沒變動過.
        else if( $preHttpTimeFloat===$httpTimeFloat && $preHttpsTimeFloat===$httpsTimeFloat && $preSmtpTimeFloat===$smtpTimeFloat && $preImapTimeFloat===$imapTimeFloat && $preNamedTimeFloat===$namedTimeFloat ){
        
                #睡一秒
                sleep(1);
                
                #debug mode
                if($debug){

                        #comment
                        echo "Log檔無變動,不做事".PHP_EOL;

                        }#if end
                
                #下一輪
                continue;
        
                }#else end

        #debug mode
        if($debug){

                #comment
                echo "Log檔有變動,要做事".PHP_EOL;
                echo "\$preHttpTimeFloat:".$preHttpTimeFloat.PHP_EOL;
                echo "\$preHttpsTimeFloat:".$preHttpsTimeFloat.PHP_EOL;
                echo "\$preSmtpTimeFloat:".$preSmtpTimeFloat.PHP_EOL;
                echo "\$preImapTimeFloat:".$preImapTimeFloat.PHP_EOL;
                echo "\$preNamedTimeFloat:".$preNamedTimeFloat.PHP_EOL;
                echo "\$httpTimeFloat:".$httpTimeFloat.PHP_EOL;
                echo "\$httpsTimeFloat:".$httpsTimeFloat.PHP_EOL;
                echo "\$smtpTimeFloat:".$smtpTimeFloat.PHP_EOL;
                echo "\$imapTimeFloat:".$imapTimeFloat.PHP_EOL;
                echo "\$namedTimeFloat:".$namedTimeFloat.PHP_EOL;

                }#if end

        #將本次http記錄覆寫到上次的記錄
        $preHttpTimeFloat=$httpTimeFloat;
        
        #將本次https記錄覆寫到上次的記錄
        $preHttpsTimeFloat=$httpsTimeFloat;
        
        #將本次smtps記錄覆寫到上次的記錄
        $preSmtpTimeFloat=$smtpTimeFloat;
                
        #涵式說明:
        #檢查 httpd 與 postfix/smtpd 的 log 與 named 的log 把惡意連線的 IP 用防火牆阻阻擋
        #回傳結果:
        #$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.
        #$result["error"],錯誤訊息.
        #$result["function"],當前執行的函數名稱.
        #$result["argu"],所使用的參數.
        #$result["found"],是否有找到符合的檔案,"true"代表有;"false"代表沒有.
        #$result["content"],找到的檔案陣列.
        #必填參數:
        #$conf["fileArgu"],字串,php變數__FILE__的內容,亦即該檔案在檔案系統的絕對路徑
        $conf["fileArgu"]=__FILE__;
        #可省略參數:
        #$conf["excludeIp"],字串陣列,白名單ip陣列.
        $conf["excludeIp"]=$excludeIp;
        #$conf["logPath"],字串,httpd的log位置,預設為 "/var/log/httpd"
        #$conf["logPath"]="";
        #$conf["username"],字串,要用什麼使用者來執行,預設為root使用者
        #$conf["username"]="";
        #$conf["password"],字串,root使用者的密碼,
        #$conf["password"]="";
        #$conf["getIplistOnly"],字串,是否不阻擋IP只取得有問題的IP,預設為"false",要阻擋IP;"true"代表只取得有問題的IP.
        #$conf["getIplistOnly"]="true";
        $blockAcctackIp=cmd::blockAcctackIp($conf);
        unset($conf);

        #如果執行失敗
        if($blockAcctackIp["status"]==="false"){

                #設置執行失敗
                $result["status"]="false";

                #設置錯誤訊息
                $result["error"]=$blockAcctackIp;

                #印出結果
                var_dump($result);
                
                #結束執行
                exit;

                }#if end
                
        #如果有執行封鎖IP的情形
        if(isset($blockAcctackIp["content"])){

                #comment
                echo "本次封鎖IP的結果如下:".PHP_EOL;
                var_dump($blockAcctackIp["content"]);
                var_dump($blockAcctackIp["reason"]);

                }#if end
                
        #睡一秒
        sleep(1);
                
        #下一輪
        continue;
        
}//while end

?>