PlusMagi's Blog By Pitt Phunsanit Linux,Network,Security Linux: ตรวจสอบความถูกต้องของระบบด้วยสปีดขั้นสุด 🚀

Linux: ตรวจสอบความถูกต้องของระบบด้วยสปีดขั้นสุด 🚀

เมื่อระบบปฏิบัติการ Linux (ตระกูล Debian/Ubuntu) ทำงานไปนาน ๆ หรือผ่านการแก้ไขไฟล์คอนฟิกมาอย่างโชกโชน คำถามที่มักตามมาคือ “มีไฟล์ระบบไหนถูกแก้ไข เปลี่ยนแปลง หรือเสียหายไปบ้าง?” โดยปกติเราสามารถใช้คำสั่ง dpkg --verify เพื่อตรวจสอบความสมบูรณ์ของไฟล์ทั้งหมดที่ติดตั้งผ่าน Package Manager ได้ แต่ข้อเสียคือมันจะพ่นข้อมูลออกมาทั้งหมด ซึ่งยากต่อการคัดกรองเฉพาะโฟลเดอร์ที่เราสนใจ (เช่น อยากดูแค่ใน /etc หรือ /usr/bin)

บทความนี้จะแนะนำให้รู้จักกับ verify-pkg-dpkg.sh สคริปต์ที่จะเปลี่ยนให้การตรวจสอบไฟล์ระบบเป็นเรื่องง่าย รวดเร็ว และสามารถกรองเส้นทาง (Path) รวมถึงกำหนดความลึก (Depth) ของไดเรกทอรีได้ตามใจสั่ง!


verify-pkg-dpkg.sh

#!/bin/bash

# ==============================================================================
# Script Name: verify-pkg-dpkg.sh
# Description: High-performance verification using native 'dpkg --verify'.
#			   Filters results by path and depth efficiently.
# Author	 : Pitt Phunsanit
# Date		 : 2026-08-09
# ==============================================================================
# MANUAL & DOCUMENTATION:
#
# OPTIONS:
#   -p <path>  : Base directory path to filter (Default: /)
#   -d <depth> : Maximum directory depth for filtering (Default: Unlimited)
#   -h		   : Display this help message
#
# EXAMPLES:
#   sudo ./verify-pkg-dpkg.sh
#   sudo ./verify-pkg-dpkg.sh -p /etc
#   sudo ./verify-pkg-dpkg.sh -p /usr/bin -d 1
# ==============================================================================

# Ensure script is running with root/sudo privileges
if [ "$EUID" -ne 0 ]; then
	echo "❌ Error: Please run this script with root privileges (sudo)."
	exit 1
fi

# Enable lastpipe so variables modified inside the while loop persist outside
shopt -s lastpipe

# Get the directory where this script is located
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")

# Default values
SEARCH_PATH="/"
MAX_DEPTH=""
ISO_DATE=$(date +%Y-%m-%d_%H%M%S)
OUTPUT_FILE="${SCRIPT_DIR}/verify-pkg-dpkg-${ISO_DATE}.txt"

# Usage help function
usage() {
	echo "Usage: $0 [-p <path>] [-d <depth>]"
	echo " -p : Specify starting directory path (Default: /)"
	echo " -d : Specify maximum search depth (integer)"
	exit 1
}

# Parse command-line arguments
while getopts "p:d:h" opt; do
	case ${opt} in
		p ) SEARCH_PATH=$OPTARG ;;
		d ) MAX_DEPTH=$OPTARG ;;
		h | ? ) usage ;;
	esac
done

# Ensure SEARCH_PATH ends with a slash for proper matching (except for / itself)
[[ "$SEARCH_PATH" != "/" ]] && SEARCH_PATH="${SEARCH_PATH%/}/"

echo "🔍 Starting high-performance system verification..."
echo "📍 Target Path : $SEARCH_PATH"
[[ -n "$MAX_DEPTH" ]] && echo "↕️ Max Depth : $MAX_DEPTH" || echo "↕️ Max Depth : Unlimited"
echo "📝 Report File : $OUTPUT_FILE"
echo "⚙️ Progress	 : Processing changed files in real-time..."
echo "---------------------------------------------------------"

# Clean/Create the output file
> "$OUTPUT_FILE"

# Open File Descriptor 3 for direct logging
exec 3>>"$OUTPUT_FILE"

# Function to calculate depth of a file path
get_depth() {
	local file_path="$1"
	local relative_path="${file_path#$SEARCH_PATH}"
	echo "${relative_path}" | tr -cd '/' | wc -c
}

# Counter for items found
MATCH_COUNT=0

# Run native dpkg --verify with unbuffered stream profiling
stdbuf -oL dpkg --verify 2>/dev/null | while read -r LINE; do
	FILE_PATH=$(echo "$LINE" | awk '{print $NF}')

	# Check if the file is within our target SEARCH_PATH
	if [[ "$FILE_PATH" == "$SEARCH_PATH"* || "$SEARCH_PATH" == "/" ]]; then

		# If MAX_DEPTH is set, verify the depth limit
		if [[ -n "$MAX_DEPTH" ]]; then
			CURRENT_DEPTH=$(get_depth "$FILE_PATH")
			if (( CURRENT_DEPTH >= MAX_DEPTH )); then
				continue
			fi
		fi

		# Print to screen instantly, log to file descriptor, and update counter
		echo "$LINE"
		echo "$LINE" >&3
		((MATCH_COUNT++))
	fi
done

exec 3>&-

echo "--------------------------------------------------"
echo "✅ Verification complete!"
echo "⚠️ Total modified files found matching criteria: $MATCH_COUNT"
echo "📂 Results saved to $OUTPUT_FILE"


🛠️ ความสามารถหลัก (Features)

  • High Performance: ประมวลผลแบบ Real-time Stream โดยใช้ stdbuf ทำให้เห็นผลลัพธ์บนหน้าจอทันที ไม่ต้องนั่งรอจนสแกนเสร็จทั้งระบบ
  • Path Filtering: เลือกเจาะจงสแกนเฉพาะไดเรกทอรีที่ต้องการได้ (เช่น ดูเฉพาะ /etc)
  • Depth Control: จำกัดความลึกในการค้นหาได้ เหมาะสำหรับกรณีที่ไม่อยากให้สคริปต์จมลึกลงไปในโฟลเดอร์ย่อยมากเกินไป
  • Auto Logging: บันทึกผลลัพธ์ลงไฟล์ Text ให้อัตโนมัติ (แยกตามวันที่และเวลา) เพื่อเอาไปใช้งานต่อหรือส่งให้ทีมตรวจสอบ

📋 ข้อกำหนดก่อนใช้งาน (Prerequisites)

  • ระบบปฏิบัติการ: Ubuntu / Debian หรือระบบที่ใช้ dpkg
  • สิทธิ์การใช้งาน: ต้องรันด้วยสิทธิ์ Root (sudo) เท่านั้น เนื่องจากต้องเข้าถึงไฟล์ระบบที่มีความปลอดภัยสูง

🚀 วิธีการใช้งาน (Usage Guide)

  1. การเตรียมสคริปต์
    นำโค้ดสคริปต์ไปบันทึกไว้ในเครื่อง (เช่น ชื่อไฟล์ verify-pkg-dpkg.sh) จากนั้นเปิด Terminal แล้วเปลี่ยนสิทธิ์ให้สคริปต์สามารถรันได้ด้วยคำสั่ง
    chmod +x verify-pkg-dpkg.sh
    2. คำสั่งและ Options ที่รองรับ
    sudo ./verify-pkg-dpkg.sh [-p <เส้นทางโฟลเดอร์>] [-d <ระดับความลึก>] [-h]
    • -p : กำหนดไดเรกทอรีเริ่มต้นที่ต้องการตรวจสอบ (หากไม่ใส่ ค่าเริ่มต้นคือ / หรือทั้งระบบ)
    • -d : กำหนดระดับความลึกสูงสุดของโฟลเดอร์ย่อย (หากไม่ใส่ จะค้นหาแบบไม่จำกัด)
    • -h : แสดงข้อความช่วยเหลือ (Help)

💡 ตัวอย่างการใช้งานจริง (Examples)

  • ตรวจสอบทั้งระบบ (Default)
    หากต้องการตรวจสอบไฟล์ที่มีการเปลี่ยนแปลงทั้งหมดในระบบ ให้รันสคริปต์โดยไม่ใส่ Options
    sudo ./verify-pkg-dpkg.sh
  • ตรวจสอบเฉพาะไฟล์คอนฟิกใน /etc
    หากต้องการดูว่ามีไฟล์คอนฟิกอะไรในโฟลเดอร์ /etc ถูกแก้ไขไปบ้าง
    sudo ./verify-pkg-dpkg.sh -p /etc
  • ตรวจสอบเฉพาะไฟล์หลักใน /usr/bin (จำกัดความลึก)
    หากต้องการตรวจสอบไฟล์ใน /usr/bin แต่ไม่อยากให้สแกนลึกลงไปในโฟลเดอร์ย่อยอื่น ๆ (ดูแค่ชั้นแรก)
    sudo ./verify-pkg-dpkg.sh -p /usr/bin -d 1

📝 ผลลัพธ์และการอ่านค่า (Output)

เมื่อสคริปต์ทำงานเสร็จสิ้น ผลลัพธ์จะถูกแสดงบนหน้าจอในรูปแบบสัญลักษณ์รหัสของ dpkg และจะระบุจำนวนไฟล์ที่พบ พร้อมทั้งแจ้งพาธของไฟล์ Log ไว้ที่บรรทัดสุดท้าย
ตัวอย่างผลลัพธ์บนหน้าจอ

🔍 Starting high-performance system verification...
📍 Target Path : /etc/
↕️ Max Depth : Unlimited
📝 Report File : /path/to/script/verify-pkg-dpkg-2026-08-09_233103.txt
⚙️ Progress     : Processing changed files in real-time...
---------------------------------------------------------
..5....M c /etc/nginx/nginx.conf
Missing   c /etc/cron.d/old-ticker
--------------------------------------------------
✅ Verification complete!
⚠️ Total modified files found matching criteria: 2
📂 Results saved to /path/to/script/verify-pkg-dpkg-2026-08-09_233103.txt

🕵️‍♂️ วิธีอ่านรหัสความผิดปกติ (Quick Cheat Sheet)

หากคุณเห็นตัวอักษรแปลก ๆ หน้าชื่อไฟล์ เช่น ..5....M หรือ Missing มันคืออะไร?

รหัสความหมาย
5ค่า MD5 checksum ไม่ตรง (เนื้อหาในไฟล์ถูกแก้ไข)
Sขนาดของไฟล์ (Size) เปลี่ยนไป
Mสิทธิ์ของไฟล์ (Permissions/Mode) หรือ Owner ถูกเปลี่ยน
Missingไฟล์นี้หายไปจากระบบ (ถูกลบ)

📌 ข้อควรระวัง

⚠️ สำคัญมาก: > สคริปต์นี้ทำหน้าที่ “ตรวจจับ” เท่านั้น ไม่ได้ทำการแก้ไขหรือกู้คืนไฟล์ให้ หากคุณพบว่าไฟล์คอนฟิกสำคัญ (เช่น nginx.conf หรือไฟล์ระบบอื่น ๆ) มีความผิดปกติ และคิดจะลง Package ใหม่ทับ ควรทำการ Backup หรือทำ Snapshot ระบบไว้ก่อนเสมอ เพื่อป้องกันไม่ให้ Config ปัจจุบันสูญหายครับ!


อ่านเพิ่มเติม