# 機能設計書 96-DHCPクライアント

## 概要

本ドキュメントは、FreeBSDのDHCPクライアント（dhclient）の機能設計を記述する。dhclientはDHCP（Dynamic Host Configuration Protocol）を使用してネットワークインタフェースにIPアドレスを自動設定するデーモンプログラムである。

### 本機能の処理概要

dhclientは、RFC 2131に基づくDHCPクライアント実装であり、ネットワークインタフェースのIPアドレス、サブネットマスク、デフォルトゲートウェイ、DNSサーバ等のネットワーク設定を自動取得する。OpenBSD由来のコードをベースに、FreeBSD固有の拡張（Capsicumサンドボックス化、権限分離等）が施されている。

**業務上の目的・背景**：ネットワーク接続時にIPアドレスを手動設定することなく、DHCPサーバから自動的にネットワーク設定を取得する必要がある。dhclientはこの自動設定機能を提供し、システム起動時やネットワーク再構成時に使用される。

**機能の利用シーン**：システム起動時の自動ネットワーク設定、bsdinstallでのインストール時IPv4設定（画面No.8のAutoモード）、ノートPC等のモバイル環境でのネットワーク接続、仮想マシンのネットワーク自動設定などで使用される。

**主要な処理内容**：
1. DHCPディスカバリ（DHCPDISCOVER）：利用可能なDHCPサーバの探索
2. DHCPオファー受信（DHCPOFFER）：サーバからのアドレス提案受信
3. DHCPリクエスト（DHCPREQUEST）：特定アドレスのリース要求
4. DHCPリース確認（DHCPACK）：リース確定・ネットワーク設定適用
5. リース更新（RENEW/REBIND）：リース期限前の更新処理
6. リリース（DHCPRELEASE）：IPアドレスの明示的解放
7. dhclient-scriptによるシステム設定反映

**関連システム・外部連携**：DHCPサーバ（ISC DHCP等）、BPF（Berkeley Packet Filter）によるパケット送受信、Capsicum/Casperによるサンドボックス化

**権限による制御**：dhclientはroot権限で起動する必要がある（BPFアクセス、ネットワーク設定変更のため）。権限分離（privsep）により、パケット処理は非特権プロセスで実行される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | IPv4設定確認画面 | 遷移先機能 | Autoモード時のDHCPによるIPv4アドレス自動取得 |

## 機能種別

ネットワーク設定（DHCPクライアントデーモン）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| インタフェース名 | char * | Yes | DHCPを有効にするネットワークインタフェース | 有効なインタフェース名 |
| -c count | int | No | DHCPリクエスト試行回数 | 正の整数 |
| -l lease-file | char * | No | リースファイルのパス | 有効なファイルパス |
| -p port | int | No | リスニングポート番号 | 1-65535（デフォルト68） |

### 入力データソース

- dhclient.conf設定ファイル（/etc/dhclient.conf）
- DHCPサーバからのDHCPパケット（UDP ポート68で受信）
- BPFデバイス経由のEthernetフレーム

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| IPアドレス | struct in_addr | DHCPサーバから取得したIPアドレス |
| サブネットマスク | struct in_addr | ネットワークマスク |
| デフォルトゲートウェイ | struct in_addr | ルータアドレス |
| DNSサーバ | struct in_addr[] | ネームサーバアドレス |
| ドメイン名 | char * | 検索ドメイン |
| リース情報 | lease構造体 | リース期間、更新時刻、バインド時刻 |

### 出力先

- ネットワークインタフェースへのIP設定適用（ifconfig経由）
- リースファイル（/var/db/dhclient.leases.*）への保存
- /etc/resolv.conf への DNS設定反映（dhclient-script経由）
- syslog への動作ログ出力

## 処理フロー

### 処理シーケンス

```
1. 初期化
   └─ 設定ファイル読み込み、BPFデバイスオープン、権限分離
2. DHCPステートマシン開始
   └─ INIT状態から開始
3. DHCPDISCOVER送信
   └─ ブロードキャストでDHCPサーバを探索
4. DHCPOFFER受信
   └─ サーバからのアドレス提案を受信・評価
5. DHCPREQUEST送信
   └─ 選択したアドレスのリースを要求
6. DHCPACK受信
   └─ リース確定、dhclient-script実行でシステム設定反映
7. BOUND状態
   └─ リース有効期間中の通常運用
8. RENEW/REBIND
   └─ T1/T2タイマーによるリース更新
```

### フローチャート

```mermaid
flowchart TD
    A[INIT: 初期化] --> B[SELECTING: DHCPDISCOVER送信]
    B --> C{DHCPOFFER受信?}
    C -->|Yes| D[REQUESTING: DHCPREQUEST送信]
    C -->|Timeout| B
    D --> E{DHCPACK受信?}
    E -->|Yes| F[BOUND: アドレス設定完了]
    E -->|DHCPNAK| B
    E -->|Timeout| B
    F --> G{T1タイマー期限?}
    G -->|Yes| H[RENEWING: ユニキャストRENEW]
    G -->|No| F
    H --> I{DHCPACK受信?}
    I -->|Yes| F
    I -->|Timeout T2| J[REBINDING: ブロードキャストREBIND]
    J --> K{DHCPACK受信?}
    K -->|Yes| F
    K -->|リース期限切れ| B
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-96-1 | デフォルトリース期間 | リース期間未指定時のデフォルトは43200秒（12時間） | DHCPサーバがリース期間を指定しない場合 |
| BR-96-2 | ローカルポート | DHCPクライアントはUDPポート68で受信 | 常時（LOCAL_PORT=68） |
| BR-96-3 | サーバポート | DHCPサーバへはUDPポート67に送信 | 常時（REMOTE_PORT=67） |
| BR-96-4 | マジッククッキー | DHCPオプション領域の先頭は\143\202\123\143 | DHCPパケット処理時 |
| BR-96-5 | 最小パケットサイズ | BOOTP最小300バイト、DHCP最小548バイト | パケット生成時 |

### 計算ロジック

リース更新タイミング: T1 = リース期間の1/2（RENEW開始）、T2 = リース期間の7/8（REBIND開始）

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

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

本機能はデータベースを使用しない。リース情報はフラットファイル（/var/db/dhclient.leases.*）に保存される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| DHCPNAK | 否定応答 | サーバがリクエストを拒否 | INIT状態に戻りディスカバリからやり直し |
| タイムアウト | 応答なし | DHCPサーバ無応答 | 指数バックオフで再試行 |
| BPFエラー | デバイスエラー | BPFデバイスオープン失敗 | エラーログ出力、終了 |

### リトライ仕様

DHCPDISCOVERは指数バックオフ（初回1秒、以降2倍、上限あり）で再送される。

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

DHCPプロトコルのトランザクションIDにより、リクエストとレスポンスの対応付けを行う。

## パフォーマンス要件

- 起動時のアドレス取得は通常数秒以内
- リース更新はバックグラウンドで実行

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

- Capsicumサンドボックス化: パケット処理後の権限制限
- 権限分離（privsep）: 特権操作と非特権パケット処理の分離
- Casper cap_syslog: サンドボックス内からのsyslogアクセス
- ホスト名検証: DHCPサーバから受信したホスト名の妥当性チェック（borderchar/middlechar/domaincharマクロ）

## 備考

- dhclient.confで要求するDHCPオプション、優先するリース条件等をカスタマイズ可能
- dhclient-scriptはシェルスクリプトであり、DHCP状態変化時に呼び出される
- FreeBSD版はOpenBSD版をベースに、Capsicum/Casper統合が追加されている

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dhcp.h | `sbin/dhclient/dhcp.h` | struct dhcp_packet（59-77行目）: DHCPメッセージの構造。op, htype, hlen, hops, xid, secs, flags, ciaddr, yiaddr, siaddr, giaddr, chaddr, sname, file, optionsフィールド。DHOオプション定数 |
| 1-2 | dhcpd.h | `sbin/dhclient/dhcpd.h` | struct option_data（85-88行目）、struct iaddr（95-98行目）: 内部データ構造。LOCAL_PORT=68, REMOTE_PORT=67 |
| 1-3 | privsep.h | `sbin/dhclient/privsep.h` | 権限分離インタフェース定義 |

**読解のコツ**: dhcp.hはプロトコル構造体の定義、dhcpd.hはクライアント内部のデータ構造定義。DHO_*定数はDHCPオプション番号。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dhclient.c | `sbin/dhclient/dhclient.c` | メインプログラム。cur_time（93行目）、default_lease_time=43200（95行目）。Capsicum/Casper統合（62-65行目）。CLIENT_PATH定義（89行目） |

**主要処理フロー**:
1. **95行目**: default_lease_time = 43200（12時間）
2. main()関数: 引数解析 → 設定ファイル読み込み → BPFデバイスオープン → 権限分離 → DHCPステートマシン開始

#### Step 3: DHCPステートマシンを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dhclient.c | `sbin/dhclient/dhclient.c` | state_init, state_selecting, state_requesting, state_bound, state_renewing, state_rebinding等の状態遷移関数 |

#### Step 4: パケット処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | packet.c | `sbin/dhclient/packet.c` | DHCPパケットの組み立て・パース |
| 4-2 | bpf.c | `sbin/dhclient/bpf.c` | BPFデバイスを通じたEthernetフレームの送受信 |
| 4-3 | dispatch.c | `sbin/dhclient/dispatch.c` | イベントディスパッチループ |

#### Step 5: 設定ファイル解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | clparse.c | `sbin/dhclient/clparse.c` | dhclient.confの解析 |
| 5-2 | conflex.c | `sbin/dhclient/conflex.c` | 設定ファイルの字句解析 |
| 5-3 | options.c | `sbin/dhclient/options.c` | DHCPオプションの処理 |

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

```
main() [dhclient.c]
    │
    ├─ clparse.c: 設定ファイル解析
    ├─ bpf.c: BPFデバイスオープン
    ├─ privsep.c: 権限分離 (fork)
    │
    ├─ dispatch.c: イベントループ
    │      │
    │      ├─ state_init()
    │      │      └─ send_discover()
    │      │             └─ packet.c: パケット組立
    │      │                    └─ bpf.c: 送信
    │      │
    │      ├─ state_selecting()
    │      │      └─ DHCPOFFER受信処理
    │      │
    │      ├─ state_requesting()
    │      │      └─ send_request()
    │      │
    │      ├─ state_bound()
    │      │      └─ dhclient-script実行
    │      │
    │      └─ state_renewing() / state_rebinding()
    │             └─ リース更新処理
    │
    └─ dhclient-script [シェルスクリプト]
           ├─ ifconfig設定
           ├─ route設定
           └─ resolv.conf更新
```

### データフロー図

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

dhclient.conf         ───▶ clparse.c: 設定解析       ───▶ 設定構造体
                              │
BPF (Ethernet)        ───▶ bpf.c: パケット受信       ───▶ DHCPパケット
DHCPサーバ応答               │
                      dispatch.c: ステートマシン
                              │
                      options.c: オプション解析       ───▶ IPアドレス等
                              │
                      dhclient-script実行             ───▶ ifconfig適用
                                                     ───▶ route設定
                                                     ───▶ resolv.conf更新
                                                     ───▶ リースファイル保存
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dhclient.c | `sbin/dhclient/dhclient.c` | ソース | メインプログラム、ステートマシン |
| dhcp.h | `sbin/dhclient/dhcp.h` | ヘッダ | DHCPプロトコル構造体定義 |
| dhcpd.h | `sbin/dhclient/dhcpd.h` | ヘッダ | 内部データ構造定義 |
| privsep.h/c | `sbin/dhclient/privsep.h` | ソース | 権限分離 |
| bpf.c | `sbin/dhclient/bpf.c` | ソース | BPFパケット送受信 |
| packet.c | `sbin/dhclient/packet.c` | ソース | パケット組み立て |
| dispatch.c | `sbin/dhclient/dispatch.c` | ソース | イベントディスパッチ |
| clparse.c | `sbin/dhclient/clparse.c` | ソース | 設定ファイル解析 |
| conflex.c | `sbin/dhclient/conflex.c` | ソース | 字句解析 |
| options.c | `sbin/dhclient/options.c` | ソース | DHCPオプション処理 |
| dhclient-script | `sbin/dhclient/dhclient-script` | スクリプト | システム設定反映 |
| dhclient.conf | `sbin/dhclient/dhclient.conf` | 設定 | サンプル設定ファイル |
| tables.c | `sbin/dhclient/tables.c` | ソース | オプションテーブル |
| convert.c | `sbin/dhclient/convert.c` | ソース | データ型変換 |
| parse.c | `sbin/dhclient/parse.c` | ソース | 汎用パーサー |
