# 機能設計書 41-IPFW

## 概要

本ドキュメントは、FreeBSD標準のステートフルファイアウォール機能であるIPFW（IP Firewall）の機能設計について記述する。IPFWはカーネル内でパケットフィルタリングを行い、ユーザ空間のipfwコマンドを通じてルールの追加・削除・表示を行う。

### 本機能の処理概要

IPFWはFreeBSDに組み込まれたパケットフィルタリングエンジンであり、ネットワークトラフィックの許可・拒否・変換を行う。

**業務上の目的・背景**：ネットワークセキュリティの確保とトラフィック制御が必要なすべてのFreeBSDシステムにおいて、不正アクセスの防止、帯域制御、NAT（ネットワークアドレス変換）などを実現するための基盤機能である。サーバやルータとして運用されるFreeBSDシステムでは、ファイアウォール機能は不可欠である。

**機能の利用シーン**：サーバ管理者がネットワークアクセスポリシーを設定する場面、ゲートウェイルータでNATを構成する場面、トラフィックシェーピングのためにdummynet（パイプ/キュー）を設定する場面、IPv4/IPv6のフィルタリングルールを管理する場面で利用される。

**主要な処理内容**：
1. ルールの追加（add）：パケットマッチング条件とアクション（allow/deny/pipe/nat等）を含むルールを追加する
2. ルールの削除（delete）：指定されたルール番号またはセットのルールを削除する
3. ルールの表示（list/show）：現在設定されているルール一覧をカウンタ付きで表示する
4. ルールセット管理（set）：ルールセットの有効化・無効化・移動を行う
5. テーブル管理（table）：IP/MACアドレスのルックアップテーブルを管理する
6. dummynet設定（pipe/queue/sched）：帯域制御・遅延シミュレーションのパイプ・キュー・スケジューラを設定する
7. NAT設定（nat config）：ネットワークアドレス変換ルールを構成する
8. NAT64/NPTv6設定：IPv6-IPv4変換やIPv6プレフィックス変換を設定する
9. カウンタ操作（zero/resetlog）：ルールのパケット/バイトカウンタをリセットする
10. ファイルからのルール読み込み：スクリプトファイルからルールを一括投入する

**関連システム・外部連携**：pfil（パケットフィルタフック）フレームワーク経由でカーネルのネットワークスタックに接続される。dummynetと連携してQoS制御を行う。NAT機能ではlibalias相当の処理を内蔵する。

**権限による制御**：ipfwコマンドの実行にはroot権限（PRIV_NETINET_IPFW）が必要。ルールの参照のみであれば一部制限が緩和される場合がある。jailコンテキストではjailごとのルールセットに制限される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | （CLIベースのためGUI画面なし） | - | ipfwコマンドラインインタフェースによる操作 |

## 機能種別

パケットフィルタリング / ルール管理（CRUD操作） / NAT変換 / トラフィック制御

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| command | string | Yes | 操作コマンド（add/delete/list/show/flush/zero/set/table/pipe/queue/nat等） | 有効なコマンド文字列であること |
| rule_number | uint16 | No | ルール番号（1-65534） | 0-65535の範囲。65535はデフォルトルール用に予約 |
| set_number | uint8 | No | ルールセット番号 | 0-30の範囲。31は予約セット |
| action | string | Yes（add時） | アクション（allow/deny/count/pipe/queue/nat/forward/skipto等） | 有効なアクションであること |
| proto | string | No | プロトコル（tcp/udp/icmp/ip等） | 有効なプロトコル名または番号 |
| src/dst | string | No | 送信元/宛先アドレス（IP/CIDR/table参照） | 有効なIPアドレスまたはテーブル参照形式 |
| options | string | No | マッチオプション（in/out/via/frag/established等） | 有効なオプション文字列 |

### 入力データソース

- コマンドライン引数（ipfwコマンド）
- ルールファイル（ipfw -p preprocessor /path/to/rules）
- IP_FW3ソケットオプション経由のバイナリルールデータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| rule_list | text | ルール一覧のテキスト表示（番号・アクション・条件・カウンタ） |
| packet_count | uint64 | ルールにマッチしたパケット数 |
| byte_count | uint64 | ルールにマッチしたバイト数 |
| dynamic_rules | text | 動的ルール（ステートフル接続追跡）の表示 |
| table_entries | text | テーブル内容の一覧表示 |
| nat_status | text | NAT設定の表示 |

### 出力先

- 標準出力（ipfwコマンド実行結果）
- カーネルルールテーブル（ルール追加時、IP_FW3ソケットオプション経由）
- syslog（ログアクション使用時）

## 処理フロー

### 処理シーケンス

```
1. コマンド解析（main.c: main()）
   └─ プログラム名判定（ipfw or dnctl）、引数パース、オプション処理
2. コマンドディスパッチ（main.c: ipfw_main()）
   └─ コマンド種別に応じてadd/delete/list/set/table/pipe/nat等のハンドラを呼び出し
3. ルール追加の場合（ipfw2.c: ipfw_add()）
   └─ ルールのパース、バイナリ形式への変換、IP_FW3ソケットオプション発行
4. カーネル処理（ip_fw_sockopt.c）
   └─ setsockopt経由でルールの登録・削除・参照を実行
5. パケットフィルタリング（ip_fw2.c: ipfw_chk()）
   └─ pfilフック経由で呼ばれ、パケットをルールチェーンと照合
6. ルールマッチ時のアクション実行
   └─ allow/deny/pipe/nat/forward等のアクションを実行
```

### フローチャート

```mermaid
flowchart TD
    A[パケット受信] --> B[pfilフック呼び出し]
    B --> C[ipfw_chk: ルールチェーン走査]
    C --> D{ルールマッチ?}
    D -->|No| E[次のルールへ]
    E --> C
    D -->|Yes| F{アクション判定}
    F -->|allow| G[パケット通過]
    F -->|deny| H[パケット破棄]
    F -->|pipe/queue| I[dummynet処理]
    F -->|nat| J[NAT変換処理]
    F -->|skipto| K[指定ルールへジャンプ]
    F -->|count| L[カウンタ加算して次ルール]
    I --> G
    J --> G
    K --> C
    L --> C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-41-01 | デフォルトルール | ルール番号65535は常に存在し、削除不可。デフォルトのallow/denyポリシーを決定する | 常時 |
| BR-41-02 | ルール評価順序 | ルールは番号の昇順に評価され、最初にマッチしたルールのアクションが適用される（countおよびskiptoを除く） | パケット処理時 |
| BR-41-03 | セット管理 | セット番号31は予約されており、disableされたルールの一時退避に使用される | セット操作時 |
| BR-41-04 | 動的ルール | keep-stateオプションにより接続の状態追跡を行い、check-stateでマッチさせる | ステートフルフィルタリング時 |

### 計算ロジック

- ルール番号の自動割り当て：前のルールの番号に自動増分値（デフォルト100）を加算
- dummynetのパイプ帯域制御：トークンバケットアルゴリズムによる帯域制限

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

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

本機能はデータベースを使用しない。カーネル内のルールチェーン（リンクリスト）およびテーブルデータ構造を直接操作する。

| 操作 | 対象データ構造 | 操作種別 | 概要 |
|-----|-------------|---------|------|
| add | ip_fw ルールチェーン | INSERT | 新規ルールをチェーンに挿入 |
| delete | ip_fw ルールチェーン | DELETE | 指定ルールをチェーンから削除 |
| list/show | ip_fw ルールチェーン | SELECT | ルール一覧の取得 |
| table add/delete | ipfw_table | INSERT/DELETE | テーブルエントリの追加・削除 |

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

#### ip_fw（ルールチェーン）

| 操作 | 項目 | 更新値・取得条件 | 備考 |
|-----|------|-----------------|------|
| INSERT | rulenum, set, cmd[], act | ユーザ指定のルール条件とアクション | ルール番号昇順で挿入 |
| DELETE | rulenum | 指定ルール番号のエントリを削除 | セット指定による一括削除も可 |
| SELECT | 全フィールド | 全ルールまたはセット指定 | カウンタ値も含む |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| EX_USAGE | 引数エラー | 不正なコマンドまたはオプション | ヘルプメッセージを表示 |
| EX_DATAERR | データエラー | 不正なルール構文、無効なIPアドレス | エラーメッセージを表示して終了 |
| EX_UNAVAILABLE | カーネルエラー | ipfwモジュール未ロード、ソケットオプション失敗 | kldloadでモジュールをロード |
| EPERM | 権限エラー | root権限なしでの操作試行 | root権限で実行 |
| EBUSY | 競合エラー | ルール更新中の同時アクセス | リトライまたは排他制御 |

### リトライ仕様

カーネル側のルール操作はロック（rwlock/rmlock）で保護されており、自動的なリトライは行わない。ユーザ空間側も単一操作のため明示的なリトライ機構は不要。

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

カーネル内のルール操作はIP_FW_RW_LOCK/IP_FW_RW_UNLOCK（rwlock）により原子性を保証する。テーブルの原子的更新（atomic）オプションにより、テーブル全体のスワップ操作もサポートされる。

## パフォーマンス要件

- ルール評価はO(n)（ルール数に比例）。skipto命令によりルールのスキップが可能
- テーブルルックアップはハッシュまたは基数木（radix tree）によるO(1)またはO(log n)
- dummynetはパケットのキューイングを伴うため遅延が発生する
- 動的ルールのルックアップはハッシュテーブルによるO(1)

## セキュリティ考慮事項

- ipfwの設定変更にはPRIV_NETINET_IPFW権限（実質root）が必要
- jail環境ではjail固有のルールセットに制限される
- デフォルトルール（65535）のポリシー（allow/deny）はカーネルコンパイルオプションで決定
- ルールファイルの読み込み時にプリプロセッサを使用する場合、プリプロセッサの安全性確認が必要
- NATルールの不適切な設定はセキュリティ上のリスクとなる

## 備考

- ipfwはFreeBSD独自のファイアウォール実装であり、PF（OpenBSD由来）やIPFilter（Darren Reed作）と並んでFreeBSDの3大ファイアウォールの一つ
- dnctlコマンドはdummynet専用のコマンドラインインタフェースで、同一バイナリから起動される
- NAT64（IPv6-IPv4変換）、NPTv6（IPv6プレフィックス変換）のサポートも含む

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

IPFWのルール構造体とコマンドラインオプション構造体を理解することが出発点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ipfw2.h | `sbin/ipfw/ipfw2.h` | cmdline_opts構造体（35-62行目）でコマンドラインオプションの状態管理を理解する。enum tokens（89-331行目）でルール構文のトークン体系を把握する |
| 1-2 | ip_fw.h | `sys/netinet/ip_fw.h` | カーネル側ルール構造体ip_fwの定義。ルールの条件（ipfw_insn）とアクションのバイナリ表現を理解する |

**読解のコツ**: ipfw2.hのenum tokensはコマンドパーサーのトークン体系を定義しており、ルール構文の全オプションが列挙されている。_s_x構造体は文字列とトークン値の対応テーブルとして各所で使用される。

#### Step 2: エントリーポイントを理解する

ユーザ空間コマンドのエントリーポイントから処理の流れを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | main.c | `sbin/ipfw/main.c` | main()関数（670-712行目）でプログラム名判定（ipfw/dnctl）とファイル読み込みモードの分岐を理解する |

**主要処理フロー**:
1. **670-712行目**: main()関数。プログラム名がdnctlかipfwかを判定し、引数がファイルパスならipfw_readfile()、そうでなければipfw_main()を呼ぶ
2. **105-510行目**: ipfw_main()関数。getoptでオプションを解析し、コマンド種別に応じてipfw_add/ipfw_delete/ipfw_list等のハンドラにディスパッチする
3. **457-474行目**: コマンドディスパッチ部分。add/show/config/set/table/enable/disable等のサブコマンドを判定

#### Step 3: ルール処理層を理解する

ルールのパースとカーネルへの投入処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ipfw2.c | `sbin/ipfw/ipfw2.c` | ipfw_add()関数でルール文字列をバイナリ形式に変換し、do_cmd()でカーネルに投入する流れを理解する |
| 3-2 | tables.c | `sbin/ipfw/tables.c` | ipfw_table_handler()でテーブル操作のコマンド処理を理解する |
| 3-3 | nat.c | `sbin/ipfw/nat.c` | ipfw_config_nat()でNAT設定のパースと投入処理を理解する |
| 3-4 | dummynet.c | `sbin/ipfw/dummynet.c` | ipfw_config_pipe()でdummynetパイプ/キュー設定を理解する |

#### Step 4: カーネルソケットオプション処理を理解する

ユーザ空間からのリクエストをカーネルがどのように処理するかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ip_fw_sockopt.c | `sys/netpfil/ipfw/ip_fw_sockopt.c` | IP_FW3 setsockoptハンドラでルールの登録・削除・参照のカーネル側処理を理解する |

**主要処理フロー**:
- ルール追加時: ユーザ空間のdo_cmd() -> setsockopt(IP_FW3) -> カーネルのipfw_ctl() -> ルールチェーンへの挿入

#### Step 5: パケットフィルタリングエンジンを理解する

カーネル内でパケットを評価するメインエンジンを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | ip_fw_pfil.c | `sys/netpfil/ipfw/ip_fw_pfil.c` | pfilフックへの登録とipfw_check_packet()エントリポイントを理解する |
| 5-2 | ip_fw2.c | `sys/netpfil/ipfw/ip_fw2.c` | ipfw_chk()関数でパケットをルールチェーンと照合する中核ロジックを理解する。ルール条件のマッチングとアクション実行の巨大なswitch文が核心 |

### プログラム呼び出し階層図

```
ipfw(ユーザ空間コマンド)
    │
    ├─ main() [main.c:670]
    │      ├─ ipfw_main() [main.c:105]
    │      │      ├─ ipfw_add() [ipfw2.c]
    │      │      ├─ ipfw_delete() [ipfw2.c]
    │      │      ├─ ipfw_list() [ipfw2.c]
    │      │      ├─ ipfw_sets_handler() [ipfw2.c]
    │      │      ├─ ipfw_table_handler() [tables.c]
    │      │      ├─ ipfw_config_pipe() [dummynet.c]
    │      │      ├─ ipfw_config_nat() [nat.c]
    │      │      └─ do_cmd() -> setsockopt(IP_FW3)
    │      └─ ipfw_readfile() [main.c:513]
    │             └─ ipfw_main() (各行に対して)
    │
カーネル空間:
    │
    ├─ ip_fw_sockopt.c: ipfw_ctl()
    │      ├─ ルール追加/削除/参照
    │      └─ テーブル操作
    │
    └─ ip_fw2.c: ipfw_chk()  ← pfil フック経由
           ├─ ルール条件マッチング
           ├─ アクション実行
           ├─ ip_fw_dynamic.c: 動的ルール管理
           ├─ ip_fw_nat.c: NAT処理
           └─ ip_dn_io.c: dummynet処理
```

### データフロー図

```
[入力]                    [処理]                         [出力]

ipfw add コマンド ───▶ main.c: ipfw_main() ───▶ カーネルルールチェーン
                       ipfw2.c: ipfw_add()        (setsockopt IP_FW3)
                       do_cmd()

ipfw list コマンド ───▶ main.c: ipfw_main() ───▶ 標準出力（ルール一覧）
                       ipfw2.c: ipfw_list()
                       do_cmd() -> getsockopt

ネットワークパケット ──▶ pfil フック ──────────▶ パケット通過/破棄/
                       ip_fw_pfil.c                 NAT変換/dummynet
                       ip_fw2.c: ipfw_chk()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| main.c | `sbin/ipfw/main.c` | ソース | ユーザ空間コマンドのエントリーポイント |
| ipfw2.h | `sbin/ipfw/ipfw2.h` | ヘッダ | コマンドラインオプション・トークン定義 |
| ipfw2.c | `sbin/ipfw/ipfw2.c` | ソース | ルール追加・削除・表示のメイン処理 |
| tables.c | `sbin/ipfw/tables.c` | ソース | テーブル管理コマンド処理 |
| nat.c | `sbin/ipfw/nat.c` | ソース | NAT設定コマンド処理 |
| dummynet.c | `sbin/ipfw/dummynet.c` | ソース | dummynetパイプ/キュー設定 |
| ipv6.c | `sbin/ipfw/ipv6.c` | ソース | IPv6固有のルール処理 |
| altq.c | `sbin/ipfw/altq.c` | ソース | ALTQ QoS連携処理 |
| ip_fw2.c | `sys/netpfil/ipfw/ip_fw2.c` | ソース | カーネルパケットフィルタリングエンジン |
| ip_fw_sockopt.c | `sys/netpfil/ipfw/ip_fw_sockopt.c` | ソース | カーネルソケットオプション処理 |
| ip_fw_pfil.c | `sys/netpfil/ipfw/ip_fw_pfil.c` | ソース | pfilフック登録・パケット入口 |
| ip_fw_dynamic.c | `sys/netpfil/ipfw/ip_fw_dynamic.c` | ソース | 動的ルール（ステートフル追跡）管理 |
| ip_fw_nat.c | `sys/netpfil/ipfw/ip_fw_nat.c` | ソース | カーネルNAT処理 |
| ip_fw_table.c | `sys/netpfil/ipfw/ip_fw_table.c` | ソース | カーネルテーブル管理 |
| ip_fw_log.c | `sys/netpfil/ipfw/ip_fw_log.c` | ソース | ログアクション処理 |
| ip_fw_private.h | `sys/netpfil/ipfw/ip_fw_private.h` | ヘッダ | カーネル内部データ構造定義 |
| ip_fw.h | `sys/netinet/ip_fw.h` | ヘッダ | IPFW共通データ構造・定数定義 |
| ip_dummynet.c | `sys/netpfil/ipfw/ip_dummynet.c` | ソース | dummynetカーネル実装 |
| ip_dn_io.c | `sys/netpfil/ipfw/ip_dn_io.c` | ソース | dummynet I/O処理 |
| ipfw.8 | `sbin/ipfw/ipfw.8` | マニュアル | ipfwコマンドのmanページ |
