# 機能設計書 101-inetd

## 概要

本ドキュメントは、FreeBSDのインターネットスーパーサーバであるinetdの機能設計を記述する。inetdは各種ネットワークサービスの起動管理を一元的に行うデーモンプロセスである。

### 本機能の処理概要

inetdは、複数のネットワークサービスを個別のデーモンとして常駐させる代わりに、単一のデーモンプロセスが指定ポートを監視し、接続要求が到着した際に対応するサービスプログラムを起動する「スーパーサーバ」である。

**業務上の目的・背景**：多数のネットワークサービスを個別にデーモンとして常駐させると、使用頻度の低いサービスでもメモリやリソースを消費し続ける。inetdはこの問題を解決し、接続要求があった時のみサービスプロセスを起動することで、システムリソースの効率的な利用を実現する。これはBSD系UNIXの伝統的なネットワークサービス管理手法である。

**機能の利用シーン**：ftpd、telnetd、tftpd等のネットワークサービスを提供するサーバにおいて、利用頻度の低いサービスをinetd経由で起動する場合に使用される。また、echo、discard、daytime、chargen等の内蔵サービスを直接提供する場合にも利用される。tcpmux機能により、公式ポート番号を持たないTCPサービスのディスパッチも行える。

**主要な処理内容**：
1. /etc/inetd.confの解析とサービステーブル(servtab)の構築
2. 各サービスに対応するソケットの作成・バインド・リッスン
3. select(2)による複数ソケットの同時監視
4. 接続要求到着時のサービスプロセスのfork/exec
5. SIGHUPシグナルによる設定ファイルの動的リロード
6. 接続レート制限・同時接続数制限の実施
7. echo/discard/time/daytime/chargen/tcpmux/auth等の内蔵サービスの提供
8. RPC (Remote Procedure Call)サービスの登録・管理
9. IPsecポリシーの設定（IPSEC有効時）

**関連システム・外部連携**：/etc/services、/etc/rpcとの連携。libwrapによるTCP Wrapperアクセス制御。syslog経由のログ出力。RPCポートマッパーとの連携。IPsecポリシーエンジンとの連携。

**権限による制御**：各サービスはinetd.confで指定されたユーザ・グループ・ログインクラスの権限で実行される。UNIXドメインソケットのサービスでは、ソケットファイルの所有者・グループ・パーミッションも設定可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLIデーモン | 主機能 | バックグラウンドデーモンとして動作、画面なし |

## 機能種別

デーモンプロセス / ネットワークサービス管理 / プロセス起動制御

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| -d | フラグ | No | デバッグモード有効化 | なし |
| -l | フラグ | No | syslogへのログ出力有効化 | なし |
| -w | フラグ | No | 外部サービスへのTCP Wrapper適用 | なし |
| -W | フラグ | No | 内蔵サービスへのTCP Wrapper適用 | なし |
| -R rate | 整数 | No | 1分間の最大起動数（デフォルト256） | 0以上の整数 |
| -a address | 文字列 | No | バインドアドレスの指定 | 有効なIPアドレスまたはホスト名 |
| -c maximum | 整数 | No | サービスごとの最大同時子プロセス数 | 0以上の整数 |
| -C rate | 整数 | No | 同一IPからの1分間あたり最大接続数 | 0以上の整数 |
| -p filename | 文字列 | No | PIDファイルのパス | 有効なファイルパス |
| -s maximum | 整数 | No | 同一IPからの最大同時接続数 | 0以上の整数 |
| configuration file | ファイルパス | No | 設定ファイル（デフォルト/etc/inetd.conf） | 読み取り可能なファイル |

### 入力データソース

- /etc/inetd.conf: サービス定義の設定ファイル
- /etc/services: サービス名とポート番号の対応表
- /etc/rpc: RPCプログラム番号の対応表
- /etc/hosts.allow, /etc/hosts.deny: TCP Wrapperアクセス制御ファイル（LIBWRAP有効時）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 子プロセス | プロセス | 接続要求に応じて起動されるサービスプロセス |
| syslogメッセージ | テキスト | サービス起動・終了・エラー等のログメッセージ |
| PIDファイル | ファイル | /var/run/inetd.pid にプロセスIDを記録 |

### 出力先

- syslog (LOG_DAEMON facility)
- /var/run/inetd.pid
- 標準エラー出力（デバッグモード時）

## 処理フロー

### 処理シーケンス

```
1. 起動・初期化
   └─ コマンドライン引数解析、syslogオープン、シグナルハンドラ設定
2. バインドアドレス解決
   └─ -aオプション指定時、指定アドレスをgetaddrinfo()で解決
3. 設定ファイル読み込み（config関数）
   └─ inetd.confを解析し、各サービスのservtab構造体を構築
4. ソケット設定（setup関数）
   └─ 各サービスに対応するソケットを作成、bind、listen
5. PIDファイル作成
   └─ pidfile_open/pidfile_writeでPIDを記録
6. メインループ（select待ち）
   └─ fd_setに登録された全ソケットをselect(2)で監視
7. 接続要求到着時の処理
   ├─ レート制限チェック（cpmip関数）
   ├─ TCP Wrapperチェック（LIBWRAP有効時）
   ├─ 内蔵サービスの場合: 直接処理関数を呼び出し
   └─ 外部サービスの場合: fork()で子プロセスを生成しexecv()で実行
8. シグナル処理
   ├─ SIGHUP: 設定ファイルリロード
   ├─ SIGCHLD: 子プロセス回収（reapchild関数）
   └─ SIGALRM: リトライタイマー処理（retry関数）
```

### フローチャート

```mermaid
flowchart TD
    A[起動] --> B[引数解析・初期化]
    B --> C[設定ファイル読み込み config]
    C --> D[各サービスのソケット設定 setup]
    D --> E[PIDファイル作成]
    E --> F{select 待ち}
    F -->|接続到着| G{レート制限チェック}
    G -->|OK| H{TCP Wrapper}
    G -->|制限超過| F
    H -->|許可| I{内蔵サービス?}
    H -->|拒否| F
    I -->|Yes| J[内蔵関数呼び出し]
    I -->|No| K[fork + execv]
    J --> F
    K --> F
    F -->|SIGHUP| C
    F -->|SIGCHLD| L[子プロセス回収]
    L --> F
    F -->|SIGALRM| M[リトライ処理]
    M --> F
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-101 | レート制限 | 1分間にTOOMANY（デフォルト256）回以上起動されたサービスは10分間無効化 | 常時 |
| BR-102 | 同時接続数制限 | se_maxchildで設定された最大同時子プロセス数を超える接続は拒否 | maxchild設定時 |
| BR-103 | IP別レート制限 | 同一IPアドレスからの1分間あたり接続数がmaxcpmを超えた場合はログ出力 | maxcpm設定時 |
| BR-104 | IP別同時接続制限 | 同一IPアドレスからの同時接続数がmaxperipを超えた場合は接続拒否 | maxperip設定時 |
| BR-105 | nowait/wait制御 | nowaitサービスは接続ごとに子プロセスを生成、waitサービスはデータグラム到着時に単一プロセスで処理 | サービス種別による |
| BR-106 | tcpmux多重化 | ポート1番でtcpmuxプロトコルにより要求されたサービス名に基づいてディスパッチ | tcpmux/tcpmux+サービス |

### 計算ロジック

- 接続ハッシュ: `hashval(char *p, int len)` でIPアドレスをハッシュし、PERIPSIZE(256)個のバケットに分配
- レート制限: `se_count`カウンタをCNT_INTVL(60秒)間隔でリセットし、`toomany`と比較

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

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

本機能はデータベースを使用しない。設定ファイル(/etc/inetd.conf)をテキストとして読み込み、インメモリのサービステーブル(servtab linked list)で管理する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| LOG_ERR | ソケット作成失敗 | socket(2)失敗 | syslogに記録、10分後にリトライ |
| LOG_ERR | バインド失敗 | bind(2)失敗 | syslogに記録、10分後にリトライ |
| LOG_ERR | fork失敗 | fork(2)失敗 | syslogに記録、接続を閉じる |
| LOG_ERR | execv失敗 | サーバプログラム実行失敗 | syslogに記録、子プロセス終了 |
| LOG_ERR | 設定ファイルオープン失敗 | inetd.confが読めない | syslogに記録 |
| LOG_WARNING | レート制限超過 | toomany回以上の起動 | サービスを10分間無効化 |

### リトライ仕様

- ソケットのbind/listen失敗時: RETRYTIME(10分)後にretry関数でリトライ
- SIGALRMタイマーでリトライキューを処理

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

該当なし。inetdはファイルベースの設定を使用し、データベーストランザクションは存在しない。

## パフォーマンス要件

- select(2)のポーリングによる低オーバーヘッドの接続監視
- 接続要求から子プロセス起動までの遅延はfork/exec時間に依存
- TOOMANY/maxcpm/maxperipによるDoS攻撃耐性の確保

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

- TCP Wrapper (libwrap)によるホストベースのアクセス制御
- サービスごとのユーザ・グループ権限での実行（setuid/setgid）
- LOGIN_CAPによるリソース制限の適用
- IPsecポリシーの適用（IPSEC有効時）
- 同一IPからの接続レート制限によるDoS緩和
- UNIXドメインソケットのファイルパーミッション制御

## 備考

- inetdは伝統的なBSD由来のスーパーサーバであり、現代のシステムではsystemdのソケットアクティベーション等に置き換えられる場面もあるが、FreeBSDでは標準のサービス管理手法として維持されている
- RPC機能はSun RPC互換のサービス登録・管理を提供する
- FAITH_TYPE（IPv6トランスレータ）は歴史的な実装として存在する

---

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

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

### 推奨読解順序

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

まず、サービステーブルの中核となるデータ構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | inetd.h | `usr.sbin/inetd/inetd.h` | servtab構造体、procinfo構造体、conninfo構造体、biltin構造体の定義 |

**読解のコツ**: `servtab`構造体(72-125行目)がinetdの中核データ構造であり、サービス名、ソケットタイプ、プロトコル、最大子プロセス数、ユーザ/グループ、サーバプログラムパス等の全設定を保持する。`se_un`共用体(94-99行目)はIPv4/IPv6/UNIXドメインソケットのアドレスを格納する。`conninfo`(58-63行目)と`procinfo`(52-56行目)はIP別接続追跡に使用される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | inetd.c | `usr.sbin/inetd/inetd.c` | main関数とメインループ |

**主要処理フロー**:
1. **316-343行目**: main関数の開始、引数解析（getoptループ）
2. **275-276行目**: CONFIG定数（/etc/inetd.conf）とPIDファイルパスの定義
3. **202-236行目**: 内部関数のプロトタイプ宣言（close_sep, config, setup, enable, disable等）
4. **187-192行目**: 定数定義（TOOMANY=256, CNT_INTVL=60, RETRYTIME=600）

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | inetd.c | `usr.sbin/inetd/inetd.c` | config(), getconfigent(), setconfig(), endconfig()関数 |

**主要処理フロー**:
- **config()**: SIGHUPで呼ばれ、設定ファイルを再読み込みし、servtabリストを更新
- **getconfigent()**: inetd.confから1エントリを読み込んでservtab構造体に格納
- **enter()**: 新しいservtabエントリをリストに追加

#### Step 4: ソケット管理と接続処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | inetd.c | `usr.sbin/inetd/inetd.c` | setup(), close_sep(), enable(), disable()関数 |

**主要処理フロー**:
- **setup()**: ソケット作成、bind、listen、fd_setへの追加
- **enable()/disable()**: select監視への追加/除去
- **search_conn(), room_conn()**: IP別接続追跡

#### Step 5: 内蔵サービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | builtins.c | `usr.sbin/inetd/builtins.c` | 内蔵サービス（echo, discard, time, daytime, chargen, tcpmux, ident）の実装 |

**主要処理フロー**:
- **74-99行目**: biltins配列でサービス名と処理関数の対応を定義
- echo_stream/echo_dg: 受信データをそのまま返す
- discard_stream/discard_dg: 受信データを破棄
- chargen_stream/chargen_dg: RFC864文字生成
- ident_stream: RFC1413 Identification Protocol

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

```
main() [inetd.c:316]
    |
    ├─ config() ─── setconfig() ─── getconfigent()
    |                    |                └─ nextline() / skip() / sskip()
    |                    └─ endconfig()
    |
    ├─ setup() ─── socket() / bind() / listen()
    |
    ├─ [メインループ: select()]
    |     |
    |     ├─ cpmip() ─── search_conn() / room_conn()
    |     |
    |     ├─ [内蔵サービス] ─── biltins[].bi_fn()
    |     |     ├─ echo_stream/dg     [builtins.c]
    |     |     ├─ discard_stream/dg  [builtins.c]
    |     |     ├─ machtime_stream/dg [builtins.c]
    |     |     ├─ daytime_stream/dg  [builtins.c]
    |     |     ├─ chargen_stream/dg  [builtins.c]
    |     |     ├─ tcpmux()           [inetd.c]
    |     |     └─ ident_stream       [builtins.c]
    |     |
    |     └─ [外部サービス] ─── fork() + execv()
    |
    ├─ reapchild() ─── waitpid() / reapchild_conn()
    |
    └─ retry() ─── setup()
```

### データフロー図

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

/etc/inetd.conf ──────▶ config()/getconfigent() ──▶ servtab リスト
                              |
/etc/services ─────────▶ matchservent() ──────────▶ ポート解決
                              |
ネットワーク接続 ──────▶ select() メインループ ───▶ fork()+execv()
                              |                        → 子プロセス
                              |
                         cpmip() ─────────────────▶ syslog メッセージ
                              |
                         biltins[].bi_fn() ───────▶ ネットワーク応答
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| inetd.c | `usr.sbin/inetd/inetd.c` | ソース | メインプログラム（main関数、設定解析、ソケット管理、メインループ） |
| inetd.h | `usr.sbin/inetd/inetd.h` | ヘッダ | データ構造定義（servtab, procinfo, conninfo, biltin） |
| builtins.c | `usr.sbin/inetd/builtins.c` | ソース | 内蔵サービス実装（echo, discard, time, daytime, chargen, tcpmux, ident） |
| pathnames.h | `usr.sbin/inetd/pathnames.h` | ヘッダ | パス定数定義（/etc/inetd.conf, /var/run/inetd.pid） |
| inetd.conf | `usr.sbin/inetd/inetd.conf` | 設定 | デフォルト設定ファイルのサンプル |
| inetd.8 | `usr.sbin/inetd/inetd.8` | マニュアル | manページ |
| Makefile | `usr.sbin/inetd/Makefile` | ビルド | ビルド設定 |
