inotify-tools + php指令碼實現Linux伺服器檔案監控並寄件提醒,
需求簡介:
由於伺服器被掛馬,經常被寫入涉敏感的html網頁,領導時常被網監請去喝茶,呵呵你懂的。所以有兩個需求,一是找出伺服器的木馬後門和修複代碼漏洞,二是監控伺服器涉及增刪改查的檔案。
第一個不在此次探討行列,故只說第二個需求。
inotify簡介:
Inotify 是一個 Linux特性,它監控檔案系統操作,比如讀取、寫入和建立。Inotify 反應靈敏,用法非常簡單,並且比 cron 任務的繁忙輪詢高效得多。學習如何將 inotify 整合到您的應用程式中,並發現一組可用來進一步自動化系統治理的命令列工具。(來自百度百科 inotify)
inotify-tools是簡化使用inotify服務的一種工具。
以下,我們開始安裝inotify-tools。
伺服器系統:centos 6.5 檔案目錄:/data/rise 實現目的:當/data/rise目錄下任何檔案發生變化時,記錄日誌並儲存。
具體操作:
一、安裝inotify-tools工具
1、查看伺服器核心是否支援inotify服務 命令:ll /proc/sys/fs/inotify #列出檔案目錄,出現下面內容,說明伺服器支援 備忘:Linux下支援inotify的核心最小為2.6.13,可以輸入命令 [ uname -a ] 查看,centOS 5.x 核心為2.6.32,預設已經支援inotify
2、安裝inotify-tools工具
yum install make gcc gcc-c++ #安裝編譯工具
inotify-tools:點我下載 上傳inotify-tools-3.14.tar.gz到/usr/local/src目錄下。
cd /usr/local/srctar -zxvf inotify-tools-3.14.tar.gz #解壓cd inotify-tools-3.14 #進入解壓目錄./configure --prefix=/usr/local/inotify #配置make #編譯make install #安裝
3、設定環境變數
echo "PATH=/usr/local/inotify/bin:$PATH" >>/etc/profile.d/inotify.shsource /etc/profile.d/inotify.sh #使設定立即生效echo "/usr/local/inotify/lib" >/etc/ld.so.conf.d/inotify.confln -s /usr/local/inotify/include /usr/include/inotify
4、修改inotify預設參數(inotify預設核心參數太小)
執行以下命令查看結果:
sysctl -a | grep max_queued_events #結果是:fs.inotify.max_queued_events = 16384sysctl -a | grep max_user_watches #結果是:fs.inotify.max_user_watches = 8192sysctl -a | grep max_user_instances #結果是:fs.inotify.max_user_instances = 128#修改上述參數為下列值sysctl -w fs.inotify.max_queued_events="99999999"sysctl -w fs.inotify.max_user_watches="99999999"sysctl -w fs.inotify.max_user_instances="65535"#修改方法vi /etc/sysctl.conf #添加以下代碼fs.inotify.max_queued_events=99999999fs.inotify.max_user_watches=99999999fs.inotify.max_user_instances=65535wq! #儲存退出
參數說明: max_queued_events: inotify隊列最大長度,如果值太小,會出現"** Event Queue Overflow **"錯誤,導致監控檔案不準確 max_user_watches: 要同步的檔案包含多少目錄,可以用:find /home/www.osyunwei.com -type d | wc -l 統計,必須保證max_user_watches值大於統計結果(這裡/home/www.osyunwei.com為同步檔案目錄) max_user_instances: 每個使用者建立inotify執行個體最大值
二、建立即時指令碼(可跳過走第三步)
mkdir -p /home/inotify #建立目錄vim /home/inotify/inotif.sh #編輯並添加以下內容 #!/bin/sh /usr/local/inotify/bin/inotifywait -mrq -e modify,create,move,delete --fromfile '/home/inotify/excludedir' --timefmt '%y-%m-%d %H:%M' --format '%T %f %e'/data/rise/ >> /tmp/rsync.txtwq! #儲存退出vim /home/inotify/excludedir #編輯並添加以下內容 /data/rise/ #要監控的目錄 @/data/rise/cache/ #要排除監控的目錄wq! #儲存退出chmod +x /home/inotify/inotif.sh #添加執行許可權vim /etc/rc.d/rc.local #編輯並在最後一行添加以下內容,開機自動啟動 sh /home/inotify/inotif.shwq! #儲存退出
reboot重啟生效
三、直接使用手動執行命令(不想建立指令碼可以走這一步) 切換到有inotifywait的目錄下或直接在命令中添加檔案路徑。 命令如下:
/usr/local/inotify/bin/inotifywait -m -r -d -o /tmp/file_change.log --timefmt '%F %T' --format '%T %w%f %e' -e close_write -e create /data/riseweb/ @/data/riseweb/data/ @/data/riseweb/riseimg/
命令解析:
/tmp/file_change.log 是日誌路徑,產生的日誌寫在這裡面。
/data/riseweb/ 是監控的檔案目錄,後面兩個@是要排除監控的目錄。
四、使用PHP指令碼監測並發送郵件
實現思路:
在/tmp檔案夾下建立一個row_mark.txt的檔案,用來儲存上一次的file_change.log的最後行數,在crontab中定時執行php指令碼,擷取file_change.log的最後行數,與row_mark檔案最後儲存的行數做對比,數字一致,說明沒有新增動作記錄。不一致,說明有新增動作記錄,讀取新行數與舊行數之間的日誌內容,排版發送郵件,並把新行數寫入row_mark.txt檔案。
實現的php指令碼代碼:
<?php/** * Created by PhpStorm. * User: jimmyRen * Date: 16/10/24 * Time: 下午1:56 * 主要作用:檢查伺服器項目目錄下是否有建立檔案或檔案夾,如果有,發送郵件通知 * 實現思路:伺服器如有建立檔案,inotify會寫在/tmp/file_change.log裡,開啟檔案,擷取最後一行的行數,如果大於0或大於上一次儲存的行數,則追加寫進行數檔案中,並發送郵件通知 */require_once(dirname(__FILE__)."/include/common.inc.php");date_default_timezone_set("PRC");$url = '/tmp/';//開啟記錄檔$change_log = file_get_contents($url.'file_change.log');//開啟記錄行數的檔案$row_log = file_get_contents($url.'row_mark.log');//將檔案以每行轉換成數組$change_array = explode("\n",$change_log);$row_array = explode("\n",$row_log);//擷取數組的總長度$change_count = count($change_array);$row_count = count($row_array);//擷取記錄檔最後一行的key[行數]$change_row = $change_count - 2;//擷取行數檔案最後一行的值$row_value = substr($row_array[$row_count-1],0,strpos($row_array[$row_count-1],"["));$row_date = date("Y-m-d H:i:s",time());if($change_row > 0 && $row_log== ""){//第一次寫行數日誌 $file_write = file_put_contents($url.'row_mark.log',$change_row."[".$row_date."]",FILE_APPEND); echo "首次寫入記錄成功";exit;}elseif($change_row > 0 && $change_row > $row_value){ $file_write2 = file_put_contents($url.'row_mark.log',"\n".$change_row."[".$row_date."]",FILE_APPEND);}else{ echo "目前時間".date("Y-m-d H:i:s", time())." 沒有新寫入的檔案"; exit;}//有新寫入的行數,把日誌新寫入的內容迴圈取出來,組建檔案,然後發送emailif($file_write2){ ini_set("memory_limit","512M"); $new_array = array(); for($i = $row_value;$i<$change_row;$i++){ $new_array[] = "\n\r\n".$change_array[$i]; } //把拿到的數群組轉換成行數格式的字串 $text = implode("\n\r\n",$new_array); $file_time = date("Y-m-d_H:i"); //把內容組建檔案 $file = fopen($url."checkChangeLog".$file_time.".txt","w+"); if($file){ iconv("UTF-8","GB2312//IGNORE",$text); $write = fwrite($file,$text); } fclose($file); //發送郵件 function sendmail($email, $mailtitle, $mailbody) { global $cfg_sendmail_bysmtp, $cfg_smtp_server, $cfg_smtp_port, $cfg_smtp_usermail, $cfg_smtp_user, $cfg_smtp_password, $cfg_adminemail,$cfg_webname; if($cfg_sendmail_bysmtp == 'Y' && !empty($cfg_smtp_server)) { $mailtype = 'TXT'; require_once(DEDEINC.'/mail.class.php'); $smtp = new smtp($cfg_smtp_server,$cfg_smtp_port,true,$cfg_smtp_usermail,$cfg_smtp_password); $smtp->debug = false; if(!$smtp->smtp_sockopen($cfg_smtp_server)){ ShowMsg('郵件發送失敗,請聯絡管理員','-1'); exit(); } $smtp->sendmail($email,$cfg_webname,$cfg_smtp_usermail, $mailtitle, $mailbody, $mailtype); }else{ @mail($email, $mailtitle, $mailbody, $headers); } } $email = "906691xxx.qq.com"; //這裡填寫要發送到的郵箱 $mailtitle = date("Y-m-d H:i", time())." rise檔案寫入情況"; $mailbody = $text; sendmail($email, $mailtitle, $mailbody); echo "指令碼執行成功!";exit;}
tip:記得載入發送郵件的class。
五、crontab定時任務
要求是每天的0 - 7點,每5個小時執行一次,7 - 21點,每1個小時執行一次,21 - 23點,每2個小時執行一次,故crontab指令碼命令如下。
#定時檢查伺服器檔案寫入情況並發送郵件通知0 0-7/5,7-21/1,21-23/2 * * * php /data/rise/checkfile.php
六、總結
需求肯定是實現了,由於不是專業的營運,本次只是實現了需求,大神們有更好的方法可交流探討。