# バッチ設計書 50-520.pfdenied

## 概要

本ドキュメントは、FreeBSDのperiodicセキュリティフレームワークにおけるpf拒否パケットログ確認バッチ `520.pfdenied` の設計仕様を記述するものである。

### 本バッチの処理概要

このバッチは、pf（Packet Filter）のブロックルールに一致したパケット統計を監視し、前回実行時からの変更を検出・報告するセキュリティ監査スクリプトである。メインアンカーに加えてblacklistd/blocklistdのサブアンカーおよびカスタムアンカーも検査対象とする。

**業務上の目的・背景**：pf（Packet Filter）はOpenBSD由来のパケットフィルタリング機構であり、FreeBSDでも広く利用されている。ブロックされたパケットの統計を定期的に確認することで、外部からの攻撃試行の検出、ファイアウォールルールの有効性確認、ネットワーク設定の問題発見を支援する。特にblacklistd/blocklistdとの連携により動的にブロックされたホストの状況も把握できる。

**バッチの実行タイミング**：日次（daily security checkの一部として実行。`security_status_pfdenied_period` のデフォルトは "daily"）

**主要な処理内容**：
1. periodic.confの読み込みとsecurity.functionsの読み込み
2. メインpfルールセットのブロックルール統計を取得
3. blacklistdアンカーのサブアンカーを列挙し、各サブアンカーのブロック統計を取得
4. blocklistdアンカーのサブアンカーを列挙し、各サブアンカーのブロック統計を取得
5. カスタムアンカー（security_status_pfdenied_additionalanchors）のブロック統計を取得
6. 全ブロックルールのうちヒットカウントが0より大きいものを抽出
7. `check_diff` 関数（new_onlyモード）で前回結果との差分を検出・報告

**前後の処理との関連**：セキュリティチェックスクリプト群の一つで、510.ipfdeniedの後、550.ipfwlimitの前に実行される。ファイアウォール関連チェックの3番目のスクリプトである。

**影響範囲**：pfの統計読み取りとカウンタリセット（`-z` オプション）を行う。カウンタリセットにより、次回実行時には差分のみが検出される。`/var/log/pf.today` および `/var/log/pf.yesterday` のログファイルを更新する。

## バッチ種別

セキュリティ監査 / ファイアウォールログレポート

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 日次（デフォルト。weekly/monthlyに変更可能） |
| 実行時刻 | daily security checkの実行時刻に準ずる |
| 実行曜日 | 該当なし |
| 実行日 | 該当なし |
| トリガー | cron経由 `periodic daily` -> `450.status-security` -> 本スクリプト |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| security_status_pfdenied_enable | "YES" であること（デフォルト: YES） |
| security_status_pfdenied_period | 実行周期が現在のPERIODICコンテキストと一致すること（デフォルト: daily） |
| security.functions | `/etc/periodic/security/security.functions` が読み込み可能であること |
| pfctl | pfctlコマンドが利用可能であること |

### 実行可否判定

`check_yesno_period security_status_pfdenied_enable` 関数により判定。pfctlコマンドの実行が成功する必要がある（pfが有効でない場合はスキップ）。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| security_status_pfdenied_enable | YES/NO | No | YES | バッチの有効/無効 |
| security_status_pfdenied_period | 文字列 | No | daily | 実行周期 |
| security_status_pfdenied_additionalanchors | 文字列 | No | （空） | 追加で検査するpfアンカー名のリスト |
| security_status_logdir | パス | No | /var/log | ログ出力ディレクトリ |
| security_status_diff_flags | 文字列 | No | -b -U 0 | diff出力時のフラグ |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| /etc/defaults/periodic.conf | シェル変数定義 | デフォルト設定値 |
| pfctl -sr -v -z 出力 | テキスト | pfルール一覧（詳細・カウンタリセット付き） |
| pfctl -a -sA 出力 | テキスト | サブアンカー一覧 |
| /var/log/pf.today | テキスト | 前回実行時のpfブロック情報 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| 標準出力 | テキスト | 新規ブロックパケットのdiff出力（new_onlyモード） |
| /var/log/pf.today | テキスト | 最新のpfブロック情報 |
| /var/log/pf.yesterday | テキスト | 前回のpfブロック情報（ローテーション） |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | pf.today / pf.yesterday |
| 出力先 | /var/log/（security_status_logdir設定に依存） |
| 文字コード | システムロケール依存 |
| 区切り文字 | スペース区切り（pfctl出力形式） |

## 処理フロー

### 処理シーケンス

```
1. 設定ファイル読み込み
   └─ periodic.confとsecurity.functionsを読み込み
2. 実行可否判定
   └─ check_yesno_period security_status_pfdenied_enable
3. 一時ファイル作成
   └─ mktemp -t security で一時ファイルを生成
4. アンカーリスト構築
   └─ "" (メイン) + blacklistdサブアンカー + blocklistdサブアンカー + 追加アンカー
5. 各アンカーのブロックルール統計取得（ループ）
   └─ pfctl -a "${_a}" -sr -v -z でルール取得（-z でカウンタリセット）
   └─ nawkでblockルールのうちヒットカウント > 0のものを抽出
   └─ 結果を一時ファイルに追記
6. 差分チェック（ブロック情報が存在する場合のみ）
   └─ check_diff new_only pf で前回結果と比較
7. クリーンアップ
   └─ 一時ファイルを削除
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B[periodic.conf読み込み]
    B --> B2[security.functions読み込み]
    B2 --> D{check_yesno_period?}
    D -->|No| K[exit 0]
    D -->|Yes| E["mktemp: 一時ファイル作成"]
    E --> F[アンカーリスト構築]
    F --> G["ループ: 各アンカーについて"]
    G --> G2["pfctl -a anchor -sr -v -z"]
    G2 --> G3["nawk: blockルールでヒット>0を抽出"]
    G3 --> G4["結果を一時ファイルに追記"]
    G4 --> G5{次のアンカーあり?}
    G5 -->|Yes| G
    G5 -->|No| H{一時ファイルにデータあり?}
    H -->|No| I["rm 一時ファイル"]
    H -->|Yes| J["check_diff new_only pf"]
    J --> J2["rc=$?"]
    J2 --> I
    I --> L[exit rc]
```

## データベース操作仕様

### 操作別データベース影響一覧

本バッチはデータベース操作を行わない。

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 該当なし | - | - | - |

### テーブル別操作詳細

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | 変更検出 | ブロックパケット統計に変更があった場合 | diff出力を確認し、攻撃の兆候や設定問題がないかを判断 |
| 3 | ファイル操作エラー | ログファイルのコピー/移動に失敗した場合 | ログディレクトリのパーミッションとディスク容量を確認 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

### 障害時対応

pfctlコマンドが失敗する場合は、pfカーネルモジュールのロード状態とpfの有効/無効を確認する。pfが有効でない環境ではコマンドが失敗し、処理が安全にスキップされる。

## トランザクション仕様

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | 該当なし |
| コミットタイミング | 該当なし |
| ロールバック条件 | 該当なし |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | pfルール数 x アンカー数に依存 |
| 目標処理時間 | 数秒以内 |
| メモリ使用量上限 | 極めて低い |

## 排他制御

pfctlの `-z` オプションによりカウンタをリセットするため、同時に複数の本バッチが実行されるとカウンタが正しく記録されない可能性がある。ただし、periodicフレームワークの仕組み上、同時実行は通常発生しない。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 差分ログ | 変更検出時 | "{host} pf denied packets:" と新規ブロックパケット情報 |
| 初回ログ | 初回実行時 | "No /var/log/pf.today" |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| pfブロックパケット変更 | 差分1件以上 | daily_status_security_output（デフォルト: root） |

## 備考

- 500.ipfwdenied/510.ipfdeniedとは異なり、pfctlの `-z` オプションによりルールのカウンタをリセットする。これにより次回実行時には差分のみが検出される
- blacklistd（旧名称）とblocklistd（新名称）の両方のアンカーを検査する後方互換性がある
- `security_status_pfdenied_additionalanchors` でカスタムアンカーを追加検査対象にできる
- nawkによるフィルタ処理は、blockルールの行を検出し、次の行（統計行）の第5フィールド（パケットカウント）が0より大きい場合のみ出力する
- `-sr` はルール表示、`-v` は詳細表示、`-z` はカウンタリセットのオプション
- ソースコード: `usr.sbin/periodic/etc/security/520.pfdenied`
