コンテンツにスキップ

🛡 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 の完全開通。およびログローテーション規律の配備を完了。