🛡 RBL・ホワイトリストの現代化規律(全知性集約)
dazoo.ne.jp 陣営の防衛規律は、2026年4月のサーバー移設を機に、MariaDB (dbispconfig) を核とした動的・リアルタイム執行システムへと進化した。
1. 知性の最前線:Sieve 正典 📜
システムへ流入する全てのメールに対し、最初に適用される規律。救済後の stop; を廃し、後続のユーザー別規律(転送設定等)への知性継承を可能とした。
① グローバル前処理 (/etc/dovecot/sieve/global_before.sieve)
require ["fileinto", "regex", "variables", "envelope", "copy"];
if envelope :is "to" ["spam_test@dazoo.ne.jp", "spam@dazoo.ne.jp"] {
keep;
stop;
}
redirect :copy "spam_test@dazoo.ne.jp";
if header :regex "X-Spamd-Result" "\[[[:space:]]*(-?[0-9.]+)" {
set "score" "${1}";
if string :regex "${score}" "^-" {
keep;
# stop; (D-Spec: Allow forwarding)
}
# 18.0点以上を隔離箱(spam@)へ
if string :regex "${score}" "^(1[8-9]|[2-9][0-9]|[0-9]{3,})" {
redirect "spam@dazoo.ne.jp";
stop;
}
}
keep;
② 処刑執行規律 (/var/vmail/dazoo.ne.jp/spam/.ispconfig.sieve)
# D-Spec Isolation Logic V30.6 - RBL & Reject Move (Threshold 25)
require ["fileinto", "comparator-i;ascii-numeric", "relational", "variables", "regex", "mailbox", "vnd.dovecot.pipe", "copy"];
if header :regex "X-Spamd-Result" "\[[[:space:]]*(-?[0-9]+)" {
set "score" "${1}";
# 規律:25点以上を RBL 登録規律にかけ、Reject フォルダへ隔離する。
if string :value "ge" :comparator "i;ascii-numeric" "${score}" "25" {
pipe :copy "register_black_ip.sh";
fileinto :create "Reject";
stop;
}
}
keep;
2. 物理結合の規律:BIND 委任(穴あけ) 🔗
BIND(Master)において、サブドメインを rbldnsd(ポート 530)へ転送させるための物理的設定。
white-domain 3600 IN NS ns.dazoo.ne.jp.
付録:執行プログラム ソースコード正典 📑
以下に s2 サーバーで稼働中の最新ソースコードを収録する。
lc_rbl_sync_all.sh
#!/bin/bash
# ==============================================================================
# D-Spec: RBL & White-RBL Master Sync Script (V1.0)
# 規律:DBからBlack/White両リストを抽出し、物理ファイルへ同期、サービスを再起動する
# ==============================================================================
PATH=/bin:/sbin:/usr/bin:/usr/sbin
RBL_DIR="/var/lib/rbldns"
BLACK_FILE="${RBL_DIR}/ip"
WHITE_FILE="${RBL_DIR}/white_ips"
TS=$(date +%Y%m%d_%H%M%S)
echo "規律執行:RBLデータベースから物理ファイルへの同期を開始します..."
# 1. ブラックリスト (ip) の生成
# 規律:例外(!)を先頭に、30日以内のアクティブなスパムIPを抽出
(mysql dbispconfig -N -s -e "SELECT concat('!', ip, ' # ', IFNULL(comment,'white')) FROM rbl_exceptions"; \
mysql dbispconfig -N -s -e "SELECT concat(ip, ' # last:', last_seen, ' cnt:', occurrence_count) FROM rbl_tracker WHERE last_seen >= DATE_SUB(NOW(), INTERVAL 30 DAY)") > ${BLACK_FILE}.new
# 2. ホワイトリスト (white_ips) の生成
# 規律:例外(!)を先頭に、90日以内のアクティブな味方IPを抽出
(mysql dbispconfig -N -s -e "SELECT concat('!', ip, ' # ', IFNULL(comment,'white')) FROM rbl_exceptions"; \
mysql dbispconfig -N -s -e "SELECT concat(ip, ' # ', IFNULL(hostname,'unknown'), ' cnt:', occurrence_count) FROM white_tracker WHERE last_seen >= DATE_SUB(NOW(), INTERVAL 90 DAY) ORDER BY ip ASC") > ${WHITE_FILE}.new
# 3. 整合性チェックと反映
if [ -s "${BLACK_FILE}.new" ] && [ -s "${WHITE_FILE}.new" ]; then
# バックアップ
cp -p "${BLACK_FILE}" "${BLACK_FILE}.${TS}"
cp -p "${WHITE_FILE}" "${WHITE_FILE}.${TS}"
# 置換
mv "${BLACK_FILE}.new" "${BLACK_FILE}"
mv "${WHITE_FILE}.new" "${WHITE_FILE}"
# 権限とリロード
chown rbldns:rbldns "${BLACK_FILE}" "${WHITE_FILE}"
systemctl reload rbldnsd
echo "[Success] RBL(Black/White) 同期完了。rbldnsd をリロードしました。"
else
echo "[Error] ファイル生成に失敗しました。処理を中断します。"
exit 1
fi
lc_rbl_update_db.sh
#!/bin/bash
# ==============================================================================
# D-Spec: RBL Master Update Script (V3.3 - Purified White Domain)
# 規律:IP(善悪) および Domain(善) のみを管理し、rbldnsd へ同期させる
# ==============================================================================
PATH=/bin:/sbin:/usr/bin:/usr/sbin
RBL_DB="/var/lib/rbldns/ip"
WHITE_IP_DB="/var/lib/rbldns/white_ips"
WD_DB="/var/lib/rbldns/white_domains"
ACTIVE_DAYS=30
MIN_COUNT=0
TMP="/tmp/ispc_rbl.tmp"
PASS=$(cat /usr/local/ispconfig/server/lib/mysql_clientdb.conf | grep password | cut -d"'" -f2)
MYSQL_CMD="mysql -u root -p$PASS dbispconfig -N -s -e"
# --- [1. IP Black 生成] ---
$MYSQL_CMD "SELECT concat('!', ip, ' # ', IFNULL(comment,'white')) FROM rbl_exceptions" > "$TMP"
$MYSQL_CMD "SELECT concat(ip, ' # last:', last_seen, ' cnt:', occurrence_count) FROM rbl_tracker WHERE last_seen >= DATE_SUB(NOW(), INTERVAL $ACTIVE_DAYS DAY) AND occurrence_count > $MIN_COUNT" >> "$TMP"
mv "$TMP" "$RBL_DB"
# --- [2. IP White 生成] ---
( $MYSQL_CMD "SELECT concat(ip, ' # ', IFNULL(comment,'master_white')) FROM rbl_exceptions";
$MYSQL_CMD "SELECT concat(ip, ' # cnt:', occurrence_count) FROM white_tracker WHERE last_seen >= DATE_SUB(NOW(), INTERVAL 90 DAY)" ) > "$TMP"
mv "$TMP" "$WHITE_IP_DB"
# --- [3. Domain White 生成 (white-domain)] ---
$MYSQL_CMD "SELECT concat(domain, ' 127.0.0.2') FROM white_domain_tracker" > "$TMP"
mv "$TMP" "$WD_DB"
# --- [4. 反映執行] ---
chown rbldns:rbldns /var/lib/rbldns/*
systemctl reload rbldnsd 2>/dev/null
IP_C=$(wc -l < "$RBL_DB")
WD_C=$(wc -l < "$WD_DB")
echo "=========================================="
echo " D-Spec RBL Master Report (V3.3)"
echo " [IP Black] $IP_C entries"
echo " [Domain White] $WD_C entries"
echo " [Status] Purified & Integrated"
echo "=========================================="
lc_process_selected_whitelist.sh
#!/bin/bash
# ==============================================================================
# D-Spec: Manual Specimen Whitelist Processor (V1.2 - Deep Search)
# 規律:ヘッダーの折り返し(Folding)を物理的に突破し、アドレスを確実に抽出する
# ==============================================================================
PASS=$(cat /usr/local/ispconfig/server/lib/mysql_clientdb.conf | grep password | cut -d"'" -f2)
SELECT_DIR="/var/vmail/dazoo.ne.jp/spam_test/Maildir/.minus4.select/cur"
PROCESSED_DIR="/var/vmail/dazoo.ne.jp/spam_test/Maildir/.minus4.select.processed/cur"
SYNC_SCRIPT="/root/lc_rbl_update_db.sh"
mkdir -p "$PROCESSED_DIR"
chown 5000:5000 "$PROCESSED_DIR"
shopt -s nullglob
FILES=("$SELECT_DIR"/*)
if [ ${#FILES[@]} -eq 0 ]; then
echo "通知:検体は存在しません。"
exit 0
fi
COUNT=0
for file in "${FILES[@]}"; do
# 規律:From または Return-Path の行と、その直後の行(折り返し)をセットでスキャン
# その中から最初に見つかったメールアドレスを抽出する
EMAIL=$(grep -iE "^(From|Return-Path):" -A 1 "$file" | grep -oE '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' | head -n 1)
DOMAIN=$(echo "$EMAIL" | cut -d'@' -f2 | tr -d '\r\n[:space:]' | tr '[:upper:]' '[:lower:]')
if [[ -n "$DOMAIN" && "$DOMAIN" =~ \. ]]; then
echo "登録執行: $DOMAIN"
mysql -u root -p$PASS dbispconfig -e "
INSERT INTO white_domain_tracker (domain, hostname, first_seen, last_seen, occurrence_count, comment)
VALUES ('$DOMAIN', 'Manual_Select', NOW(), NOW(), 1, 'Deep Extracted by V1.2')
ON DUPLICATE KEY UPDATE last_seen = NOW(), occurrence_count = occurrence_count + 1;"
mv "$file" "$PROCESSED_DIR/"
((COUNT++))
else
echo "警告:ドメイン抽出失敗(スキップ): $(basename "$file")"
fi
done
if [ $COUNT -gt 0 ]; then
echo "通知:$COUNT 件を登録完了。DNS同期を執行します..."
bash "$SYNC_SCRIPT"
chown -R 5000:5000 "/var/vmail/dazoo.ne.jp/spam_test/Maildir/.minus4.select.processed/"
echo "[Success] 執行完了。"
fi
register_black_ip.sh
#!/bin/bash
# ==============================================================================
# D-Spec: RBL Immediate Enforcement Script (V1.2)
# 規律:高スコア検体をDBへ登録し、即座に物理RBLファイルへ同期する
# ==============================================================================
PATH=/bin:/sbin:/usr/bin:/usr/sbin
RBL_DB="/var/lib/rbldns/ip"
RBL_TMP="/tmp/ip.tmp"
GOLD_IP="/etc/postfix/gold_ip.txt"
EX_IP="^(192\.168\.|127\.0\.|116\.199\.244\.|116\.199\.249\.|10\.|210\.237\.157\.229)"
LOG_FILE="/var/log/honeypot_trapped.log"
CONF="/usr/local/ispconfig/server/lib/config.inc.php"
DB_USER=$(grep "['\"]db_user['\"]" "$CONF" | sed -n "s/.*=[[:space:]]*['\"]\(.*\)['\"];.*/\1/p" | head -n 1)
DB_PASS=$(grep "['\"]db_password['\"]" "$CONF" | sed -n "s/.*=[[:space:]]*['\"]\(.*\)['\"];.*/\1/p" | head -n 1)
T_MAIL=$(mktemp)
cat > "$T_MAIL"
# 配送元IPの抽出(Receivedヘッダーから最初に見つかる外部IPを狙う)
ip=$(grep -I -oE "\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\]" "$T_MAIL" | tr -d '[]' | \
grep -vE "$EX_IP" | tail -n 1)
if [ -n "$ip" ]; then
if ! grep -q "^$ip" "$GOLD_IP" 2>/dev/null; then
# 1. データベースへの即時記録
mysql -u"$DB_USER" -p"$DB_PASS" dbispconfig -e "INSERT INTO rbl_tracker (ip, hostname, first_seen, last_seen, occurrence_count) VALUES ('$ip', 'realtime-trapped', NOW(), NOW(), 1) ON DUPLICATE KEY UPDATE last_seen = NOW(), occurrence_count = occurrence_count + 1;"
# 2. 物理同期(occurrence_count > 0 の制約を撤廃)
(mysql -u"$DB_USER" -p"$DB_PASS" dbispconfig -N -s -e "SELECT concat('!', ip, ' # ', IFNULL(comment,'white')) FROM rbl_exceptions"; \
mysql -u"$DB_USER" -p"$DB_PASS" dbispconfig -N -s -e "SELECT concat(ip, ' # last:', last_seen, ' cnt:', occurrence_count) FROM rbl_tracker WHERE last_seen >= DATE_SUB(NOW(), INTERVAL 30 DAY)") > "$RBL_TMP"
# 3. 物理反映(権限があれば直接mv)
if [ -s "$RBL_TMP" ]; then
sudo /usr/bin/cp "$RBL_TMP" "$RBL_DB"
sudo /usr/bin/systemctl reload rbldnsd
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Trapped & Synced: $ip" >> "$LOG_FILE"
fi
rm -f "$RBL_TMP"
fi
fi
rm -f "$T_MAIL"
8. 運用維持規律:ログの世代管理 (Logrotate) 🗑
リアルタイム執行ログの肥大化を防ぐため、以下の規律を /etc/logrotate.d/dazoo-rbl へ配備済み。
- 対象:
/var/log/honeypot_trapped.log - 規律: 週次回転、12世代保持、圧縮適用、vmail権限維持。
履歴備考: 2026-08-18 即時執行規律 V18.4 の完全開通。およびログローテーション規律の配備を完了。