# 機能設計書 38-BPF（パケットフィルタ）

## 概要

本ドキュメントは、FreeBSDカーネルにおけるBerkeley Packet Filter (BPF)の機能設計書である。BPFはユーザ空間からの低レベルパケットキャプチャ機構を提供する。

### 本機能の処理概要

BPFはネットワークインタフェースを通過する全てのパケットを傍受し、フィルタリングした上でユーザ空間のアプリケーションに配信する機構である。tcpdump、libpcap、dhclient等のネットワークツールの基盤技術である。

**業務上の目的・背景**：ネットワークのトラブルシューティング、セキュリティ監視、プロトコル解析、ネットワーク統計収集などの目的で、生のパケットデータにアクセスする必要がある。BPFはこれらの要求に対して、カーネル内でのフィルタリングによる効率的なパケットキャプチャを実現する。

**機能の利用シーン**：tcpdumpによるパケットキャプチャ、dhclientによるDHCPパケット送受信、Wiresharkによるネットワーク解析、侵入検知システム（IDS）のパケット監視、ネットワーク監視ツールで利用される。

**主要な処理内容**：
1. ネットワークインタフェースへのアタッチ（BIOCSETIF ioctl）
2. BPFフィルタプログラムの設定（BIOCSETF ioctl）
3. パケットのキャプチャ（read()による読み出し）
4. パケットの注入（write()によるフレーム送信）
5. バッファ管理（ストアバッファとホールドバッファのダブルバッファリング）
6. タイムスタンプ処理
7. BPF JIT（Just-In-Time）コンパイラによるフィルタの最適化
8. ゼロコピーバッファモード
9. 即時モード（BIOCIMMEDIATE）
10. プロミスキャスモード制御

**関連システム・外部連携**：ネットワークインタフェース層、libpcap、tcpdump、dhclient、netgraph（ng_bpf）

**権限による制御**：/dev/bpfデバイスへのアクセス権限に基づく。通常、bpfグループまたはroot権限が必要。MACフレームワークによる追加のアクセス制御も適用される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | カーネル機能のため該当する画面なし |

## 機能種別

カーネルパケットキャプチャ機構（パケット傍受 / フィルタリング / 配信）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| BIOCSETIF | struct ifreq | Yes | アタッチするIF指定 | 存在するIF名 |
| BIOCSETF | struct bpf_program | No | フィルタプログラム | 有効なBPF命令列 |
| BIOCSBLEN | u_int | No | バッファサイズ | 正の整数 |
| BIOCIMMEDIATE | u_int | No | 即時モード有効化 | 0/1 |
| BIOCPROMISC | - | No | プロミスキャスモード有効化 | - |

### 入力データソース

ユーザ空間アプリケーション（/dev/bpfデバイスへのioctl/read/write）、ネットワークインタフェース（受信パケット）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| キャプチャデータ | bpf_hdr + パケット | タイムスタンプ・長さ情報付きのパケットデータ |
| 統計情報 | struct bpf_stat | 受信パケット数、ドロップパケット数 |

### 出力先

ユーザ空間バッファ（read()経由）

## 処理フロー

### 処理シーケンス

```
1. ユーザプロセスが/dev/bpfをopen()
   └─ bpf_d（BPFディスクリプタ）が割り当てられる
2. BIOCSETIF ioctlでインタフェースにアタッチ
   └─ bpf_if構造体のdlistにディスクリプタを追加
3. BIOCSETF ioctlでフィルタプログラムを設定（オプション）
   └─ BPF命令列の検証、JITコンパイル
4. NICがパケットを受信
   └─ bpf_mtap()/bpf_mtap2()が呼ばれる
5. フィルタプログラムでパケットを評価
   └─ マッチした場合のみバッファにコピー
6. ユーザプロセスがread()でバッファを読み出し
   └─ ストアバッファとホールドバッファの切替
```

### フローチャート

```mermaid
flowchart TD
    A[パケット受信] --> B[bpf_mtap]
    B --> C{フィルタ評価}
    C -->|マッチ| D[ストアバッファにコピー]
    C -->|不一致| E[破棄]
    D --> F{バッファ満杯?}
    F -->|Yes| G[ストア→ホールド切替]
    F -->|No| H[待機]
    G --> I[read可能通知]

    J[ユーザread] --> K[ホールドバッファ読出]
    K --> L[バッファクリア]

    M[ユーザwrite] --> N[フレーム構築]
    N --> O[IF出力]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-38-01 | ダブルバッファリング | ストアバッファ（書込先）とホールドバッファ（読出先）を交互に切替 | 常時 |
| BR-38-02 | カーネル内フィルタリング | BPFフィルタプログラムがカーネル内で実行され、不要パケットの除外を効率的に行う | フィルタ設定時 |
| BR-38-03 | 即時モード | BIOCIMMEDIATEが設定された場合、パケット到着時にすぐにread可能になる | 即時モード有効時 |
| BR-38-04 | DLTマッチング | アタッチ時にデータリンクタイプ（DLT）が一致するインタフェースのみ使用可能 | BIOCSETIF時 |

### 計算ロジック

BPFフィルタはレジスタマシンベースの命令セットで記述される。各命令はopcode, jt, jf, kの4フィールドで構成。

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

該当なし

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ENXIO | デバイスなし | 存在しないIFを指定 | IF名確認 |
| EINVAL | 無効フィルタ | 不正なBPFプログラム | フィルタプログラム確認 |
| EACCES | 権限不足 | /dev/bpfへのアクセス権なし | bpfグループ追加またはroot実行 |
| ENOBUFS | バッファ不足 | パケットバッファが不足 | BIOCSBLEN増加 |

### リトライ仕様

なし。パケットドロップはstatisticsで計数される。

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

該当なし

## パフォーマンス要件

- BPF JITコンパイラによりフィルタ実行速度を最適化
- ゼロコピーバッファモードによりカーネル-ユーザ間のデータコピーを削減
- ストアバッファへの書込はパケット受信パスのホットパスにあるため、最小限のオーバーヘッドが要求される

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

- /dev/bpfデバイスのパーミッションによるアクセス制御
- MACフレームワーク（mac_framework.h）による強制アクセス制御
- BPFフィルタプログラムの検証（無限ループ防止、メモリアクセス範囲チェック）
- jail環境でのBPFアクセス制限
- ユーザ指定フィルタのカーネル内実行に対する安全性保証

## 備考

BPFはSteven McCanne and Van JacobsonによるStanford/CMU enet packet filterから派生した。FreeBSDのBPF実装は/dev/bpfデバイス（クローンデバイス）を通じてアクセスされる。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | bpf.h | `sys/net/bpf.h` | struct bpf_hdr（パケットヘッダ）、struct bpf_program（フィルタプログラム）、BIOCioctlコマンド定義 |
| 1-2 | bpfdesc.h | `sys/net/bpfdesc.h` | struct bpf_d（BPFディスクリプタ） |
| 1-3 | bpf.c | `sys/net/bpf.c` | struct bpf_if（インタフェースバインディング） |

**読解のコツ**: bpf_ifがインタフェースとBPFの結合を表し、bpf_dが個々のキャプチャセッション（ディスクリプタ）を表す。bpf_ifのbif_dlistにbpf_dのリストがつながる。

#### Step 2: BPFデバイス操作を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | bpf.c | `sys/net/bpf.c` | bpfopen(), bpfioctl(), bpfread(), bpfwrite() |

**主要処理フロー**:
1. **86行目**: MALLOC_DEFINE(M_BPF) - BPFメモリ確保タグ
2. **88-99行目**: struct bpf_if定義 - bif_dlist, bif_wlist, bif_methods等

#### Step 3: パケットキャプチャパスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | bpf.c | `sys/net/bpf.c` | bpf_mtap(), bpf_mtap2() - NICドライバから呼ばれるタップポイント |

#### Step 4: バッファ管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | bpf_buffer.c | `sys/net/bpf_buffer.c` | 標準バッファ管理（ダブルバッファリング） |
| 4-2 | bpf_zerocopy.c | `sys/net/bpf_zerocopy.c` | ゼロコピーバッファモード |

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

```
[ユーザ空間]
open(/dev/bpf) → bpfopen() [bpf.c]
    |
ioctl(BIOCSETIF) → bpfioctl() → bpf_setif()
    |                               +-- bpf_if作成/検索
    |                               +-- bpf_dにアタッチ
ioctl(BIOCSETF) → bpf_setf()
    |               +-- BPFプログラム検証
    |               +-- JITコンパイル（有効時）
    |
[パケット受信パス]
NICドライバ → bpf_mtap() / bpf_mtap2()
    +-- bpf_filter() / JIT実行 - フィルタ評価
    +-- catchpacket() - バッファへコピー
    +-- bpf_buffull() → ストア→ホールド切替
    |
read() → bpfread()
    +-- ホールドバッファの内容を返却
    |
write() → bpfwrite()
    +-- フレーム構築 → if_output()
```

### データフロー図

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

NIC受信パケット ──────> bpf_mtap()
                            |
                       bpf_filter() ──> フィルタ評価
                            |
                       [マッチ]
                            |
                       catchpacket() ──> ストアバッファ
                            |
                       バッファ切替 ──> ホールドバッファ
                            |
ユーザread() ─────────> bpfread() ──> ユーザバッファ
                            |
                       bpf_hdr + パケットデータ

ユーザwrite() ────────> bpfwrite() ──> IF出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| bpf.c | `sys/net/bpf.c` | ソース | BPFデバイスドライバ主処理 |
| bpf.h | `sys/net/bpf.h` | ヘッダ | BPF構造体・ioctl・フィルタ命令定義 |
| bpfdesc.h | `sys/net/bpfdesc.h` | ヘッダ | BPFディスクリプタ定義 |
| bpf_buffer.c | `sys/net/bpf_buffer.c` | ソース | 標準バッファ管理 |
| bpf_zerocopy.c | `sys/net/bpf_zerocopy.c` | ソース | ゼロコピーバッファ |
| bpf_jitter.h | `sys/net/bpf_jitter.h` | ヘッダ | BPF JITインタフェース |
| bpf_filter.c | `sys/net/bpf_filter.c` | ソース | BPFフィルタインタプリタ |
