# 帳票設計書 23-sockstat - オープンソケットレポート

## 概要

本ドキュメントは、FreeBSDのsockstatコマンドが出力するオープンソケットレポートの帳票設計書である。sockstatはシステム上のオープンソケットの一覧をプロセス情報と共に表示する。

### 本帳票の処理概要

sockstatコマンドは、sysctl経由でカーネルからソケット情報とファイルディスクリプタ情報を収集し、プロセスとソケットの対応関係をテーブル形式でレポートする。Capsicumサンドボックス内で動作し、Casperサービスを通じて必要な情報にアクセスする。

**業務上の目的・背景**：ネットワーク接続のトラブルシューティング、ポート使用状況の確認、セキュリティ監査において、どのプロセスがどのポートを使用しているかを把握することは重要である。sockstatはnetstatとは異なりプロセス情報を直接対応付けて表示する。

**帳票の利用シーン**：ポート競合の調査、不審な外部接続の検出、ファイアウォールルール策定の参考情報収集、サービス稼働状況の確認などで使用される。

**主要な出力内容**：
1. USER: ソケットを所有するユーザー名
2. COMMAND: プロセスのコマンド名
3. PID: プロセスID
4. FD: ファイルディスクリプタ番号
5. PROTO: プロトコル（tcp4, tcp6, udp4, udp6, sctp等）
6. LOCAL ADDRESS: ローカルアドレスとポート
7. FOREIGN ADDRESS: リモートアドレスとポート
8. CONN STATE: 接続状態（TCP/SCTP）

**帳票の出力タイミング**：コマンドラインからsockstatコマンドを実行した時点で即座に出力される。

**帳票の利用者**：ネットワーク管理者、システム管理者、セキュリティ監査担当者

## 帳票種別

一覧表（テキスト/JSON/XML形式のテーブル出力）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | コマンドライン | ターミナル | `sockstat [オプション]` 実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト / JSON / XML（libxo経由） |
| 用紙サイズ | N/A（ターミナル出力） |
| 向き | N/A |
| ファイル名 | N/A（標準出力） |
| 出力方法 | 標準出力（stdout） |
| 文字コード | ロケール依存（通常UTF-8） |

## 帳票レイアウト

### レイアウト概要

sockstatの出力はヘッダー行と明細行から構成されるテーブルである。-wオプション使用時はカラム幅が自動調整される。

```
┌──────────────────────────────────────────────────────────┐
│ USER  COMMAND  PID  FD PROTO LOCAL ADDRESS FOREIGN ADDRESS│
├──────────────────────────────────────────────────────────┤
│ root  sshd    1234  3 tcp4  *:22          *:*            │
│ www   httpd   5678  4 tcp6  *:80          *:*            │
│              ...                                         │
└──────────────────────────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | USER | ソケット所有ユーザー名 | xfile.xf_uid → passwd変換 | 文字列（左寄せ） |
| 2 | COMMAND | プロセスコマンド名 | kern.proc.pid → ki_comm | 文字列（左寄せ） |
| 3 | PID | プロセスID | xfile.xf_pid | 整数（右寄せ） |
| 4 | FD | ファイルディスクリプタ番号 | xfile.xf_fd | 整数（右寄せ） |
| 5 | PROTO | プロトコル名 | sock.protoname + vflag | 文字列（左寄せ） |
| 6 | LOCAL ADDRESS | ローカルアドレス:ポート | sock.laddr | addr:port |
| 7 | FOREIGN ADDRESS | リモートアドレス:ポート | sock.faddr | addr:port |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | USER | ユーザー名 | cap_getpwuid() | 左寄せ | 自動計算(-w) |
| 2 | COMMAND | コマンド名 | getprocname() | 左寄せ10文字切り詰め | 10文字 |
| 3 | PID | プロセスID | xf_pid | 右寄せ | 自動計算(-w) |
| 4 | FD | FD番号 | xf_fd | 右寄せ | 自動計算(-w) |
| 5 | PROTO | プロトコル | protoname+vflag | 左寄せ | 自動計算(-w) |
| 6 | LOCAL ADDRESS | ローカルアドレス | formataddr() | 左寄せ21文字 | 21文字(デフォルト) |
| 7 | FOREIGN ADDRESS | リモートアドレス | formataddr() | 左寄せ21文字 | 21文字(デフォルト) |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| N/A | なし | フッターは出力されない | - | - |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| -4 | IPv4ソケットのみ表示 | No |
| -6 | IPv6ソケットのみ表示 | No |
| -u | UNIXドメインソケット表示 | No |
| -l | LISTENソケットのみ | No |
| -c | 接続済みソケットのみ | No |
| -L | ループバック除外 | No |
| -p ポート | 指定ポートでフィルタ | No |
| -P プロトコル | 指定プロトコルでフィルタ | No |
| -j jailID | 指定jail内のみ | No |
| -F uid/username | 指定ユーザーのみ | No |
| -s | 接続状態を表示 | No |
| -S | TCPスタック名を表示 | No |
| -C | 輻輳制御アルゴリズム名を表示 | No |
| -A | PCBカーネルアドレスを表示 | No |
| -w | カラム幅自動調整 | No |
| -n | UID数値表示（名前解決なし） | No |
| -q | ヘッダー非表示 | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | ファイルテーブル順 | テーブル順 |

### 改ページ条件

テキスト出力のため改ページなし。

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| net.inet.tcp.pcblist（sysctl） | TCP PCB一覧取得 | なし |
| net.inet.udp.pcblist（sysctl） | UDP PCB一覧取得 | なし |
| net.inet.sctp.assoclist（sysctl） | SCTP関連情報取得 | なし |
| net.local.stream.pcblist（sysctl） | UNIXストリームソケット | なし |
| net.local.dgram.pcblist（sysctl） | UNIXデータグラムソケット | なし |
| net.local.seqpacket.pcblist（sysctl） | UNIXシーケンスパケットソケット | なし |
| kern.file（sysctl） | ファイルテーブル | socket KVAで結合 |
| kern.proc.pid（sysctl） | プロセス名取得 | PIDで指定 |
| passwd DB（Casper経由） | UID→ユーザー名変換 | UIDをキーに検索 |

### テーブル別参照項目詳細

#### kern.file（sysctl）

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| xf_data | ソケットKVA | 全件取得 | sock構造体とのマッチングキー |
| xf_pid | PID | 全件取得 | プロセスID |
| xf_uid | USER | 全件取得 | UID→名前変換 |
| xf_fd | FD | 全件取得 | ファイルディスクリプタ番号 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| N/A | 計算項目なし | - | カーネルから取得した値を表示 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[コマンド実行] --> B[xo_parse_args - libxo初期化]
    B --> C[getopt - オプション解析]
    C --> D[Capsicum/Casper初期化]
    D --> E[gather_sctp - SCTP情報収集]
    E --> F[gather_inet - TCP/UDP情報収集]
    F --> G[gather_unix - UNIXソケット情報収集]
    G --> H[getfiles - ファイルテーブル取得]
    H --> I[display - 表示処理]
    I --> J[xo_finish - 終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| Casper初期化失敗 | Casperデーモン接続失敗 | "Unable to contact Casper" | Casperデーモンの状態確認 |
| sysctl失敗 | カーネル情報取得失敗 | xo_err出力 | システム状態を確認 |
| データ不整合 | 取得中にデータ変更 | 警告出力（verbose時） | 再実行 |
| 無効なjail ID | 不正なjail ID指定 | jail_getid エラー | 正しいjail IDを指定 |
| サイズ不一致 | カーネル構造体サイズ不一致 | xo_warnx/xo_errx | カーネルとユーザーランドのバージョン確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数百〜数千ソケット |
| 目標出力時間 | 数秒以内 |
| 同時出力数上限 | 制限なし |

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

- Capsicumサンドボックス内で動作し、必要最小限のケイパビリティのみを使用
- Casperサービス（system.net, system.netdb, system.sysctl, system.pwd）経由でリソースにアクセス
- cap_net_limit()でネットワーク名前解決のケイパビリティを制限（CAPNET_ADDR2NAMEのみ）
- cap_pwd_limit_cmds/fieldsでpasswdアクセスを制限
- jail内プロセスの情報はjailオプションで制御

## 備考

- sockstatはlibxo(3)対応のため、--libxo json等でJSON出力可能
- RBツリー（Red-Black Tree）を使用してソケットとファイルの対応関係を効率的に管理
- SOCKSTAT_XO_VERSIONは"1"と定義されている（sockstat.c 行79）
- -wオプションにより、カラム幅が内容に応じて自動調整される

---

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

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

### 推奨読解順序

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

sockstatは複数のRBツリー構造体を使用してソケット情報を管理する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sockstat.c | `usr.bin/sockstat/sockstat.c` | struct sock（行139-161）: ソケット情報構造体。socket KVA、PCB、プロトコル、状態、アドレスを保持。RBツリーとSLISTの両方で管理される |
| 1-2 | sockstat.c | `usr.bin/sockstat/sockstat.c` | struct addr（行125-137）: アドレス情報構造体。sockaddr_storageとUNIXドメイン用のconn/ref情報を共用体で保持 |
| 1-3 | sockstat.c | `usr.bin/sockstat/sockstat.c` | struct file（行181-187）: ファイルテーブルエントリ。xf_data（ソケットKVA）をキーにRBツリーで管理 |
| 1-4 | sockstat.c | `usr.bin/sockstat/sockstat.c` | struct col_widths（行1213-1231）: カラム幅管理構造体。-wオプション時の動的カラム幅計算に使用 |

**読解のコツ**: RB_GENERATE_STATICマクロ（行169, 177, 195）でRBツリー操作関数が自動生成される。socket_compare/pcb_compare/file_compare関数がツリーの比較関数。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | sockstat.c | `usr.bin/sockstat/sockstat.c` | main()関数（行1877-2060）。Capsicum/Casper初期化、プロトコルごとのgather関数呼び出し、display()で出力 |

**主要処理フロー**:
1. **行1887-1888**: xo_parse_args()でlibxo初期化
2. **行1896-1981**: getopt()による多数のオプション解析
3. **行2004-2021**: Capsicum/Casper初期化（cap_init, cap_service_open等）
4. **行2044-2050**: IPv4/IPv6プロトコルのgather_sctp/gather_inet呼び出し
5. **行2052-2056**: UNIXドメインソケットのgather_unix呼び出し
6. **行2057**: getfiles()でファイルテーブル取得
7. **行2058**: display()で全情報を出力

#### Step 3: データ収集処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sockstat.c | `usr.bin/sockstat/sockstat.c` | gather_inet()（行620-785）: TCP/UDP/UDPLITE/DIVERTのPCBリストをsysctl経由で取得し、sock構造体に変換してRBツリーに挿入 |
| 3-2 | sockstat.c | `usr.bin/sockstat/sockstat.c` | gather_sctp()（行351-618）: SCTP関連情報をsysctl経由で取得 |
| 3-3 | sockstat.c | `usr.bin/sockstat/sockstat.c` | gather_unix()（行787-877）: UNIXドメインソケット情報を取得 |
| 3-4 | sockstat.c | `usr.bin/sockstat/sockstat.c` | getfiles()（行879-923）: kern.fileからファイルテーブルを取得し、RBツリーに格納 |

#### Step 4: 表示処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | sockstat.c | `usr.bin/sockstat/sockstat.c` | display()（行1623-1777）: ファイルテーブルとソケットRBツリーをマッチングし、xo_emit()で出力 |
| 4-2 | sockstat.c | `usr.bin/sockstat/sockstat.c` | display_sock()（行1409-1621）: 個別ソケットの詳細表示。プロトコル、アドレス、状態等を出力 |
| 4-3 | sockstat.c | `usr.bin/sockstat/sockstat.c` | formataddr()（行925-976）: アドレスのフォーマット処理 |

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

```
main() [sockstat.c 行1877]
    │
    ├─ xo_parse_args() - libxo初期化 [行1887]
    ├─ getopt() - オプション解析 [行1896]
    ├─ cap_init() - Capsicum初期化 [行2004]
    ├─ cap_service_open() x4 - Casperサービス [行2009-2020]
    │
    ├─ gather_sctp() [行351] - SCTP PCB収集
    │      └─ cap_sysctlbyname("net.inet.sctp.assoclist")
    │
    ├─ gather_inet(proto) [行620] - TCP/UDP PCB収集
    │      └─ cap_sysctlbyname("net.inet.tcp.pcblist"等)
    │
    ├─ gather_unix(proto) [行787] - UNIXソケット収集
    │      └─ cap_sysctlbyname("net.local.*.pcblist")
    │
    ├─ getfiles() [行879] - ファイルテーブル取得
    │      └─ cap_sysctlbyname("kern.file")
    │
    └─ display() [行1623] - 表示処理
           ├─ calculate_column_widths() [行1362]
           ├─ display_sock() [行1409]
           │      ├─ formataddr() [行925]
           │      ├─ sctp_conn_state() / tcpstates[]
           │      └─ xo_emit()
           └─ xo_finish()
```

### データフロー図

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

net.inet.tcp.pcblist ───▶ gather_inet(TCP)    ──┐
net.inet.udp.pcblist ───▶ gather_inet(UDP)    ──┤
net.inet.sctp.*      ───▶ gather_sctp()       ──┤──▶ socks RBツリー
net.local.*.pcblist  ───▶ gather_unix()       ──┘

kern.file            ───▶ getfiles()          ──────▶ ftree RBツリー
                                                     │
                                                     ▼
passwd DB            ───▶ cap_getpwuid()      ──▶ display()
kern.proc.pid        ───▶ getprocname()       ──▶    │
                                                     ▼
                                                 標準出力
                                                 (text/json/xml)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| sockstat.c | `usr.bin/sockstat/sockstat.c` | ソース | 主要ロジック全体（2060行） |
| sockstat.h | `usr.bin/sockstat/sockstat.h` | ヘッダー | ポートフィルタ関連の宣言 |
| Makefile | `usr.bin/sockstat/Makefile` | ビルド | ビルド設定 |
