§1概要
RoamSwitch for Linux は、macOS 版 RoamSwitch のゼロトラスト・ネットワーク防衛思想を Linux(systemd + nftables 環境)向けに完全実装した、常駐型のネットワークセキュリティ&システム診断ソフトウェアです。
接続中の Wi-Fi / 有線ネットワークをゲートウェイ MAC アドレス単位で識別し、nftables のファイアウォールプロファイルを自律的に切り替えます。加えて、ランサムウェアの挙動検知(fanotify + シャノンエントロピー + カナリア)、BadUSB 対策、20 項目のセキュリティ健全性診断、Model Context Protocol(MCP)サーバーを標準搭載します。
本書は、アーキテクチャ・脅威モデル・各防衛機構の設計、そして 「完全ローカル処理・外部送信データゼロ」 という原則がどのようにコードレベルで担保されているかを説明します。宣伝的な表現は避け、記載内容はすべて配布中のソースおよび実際の動作から確認できるようにしています(付録参照)。
| 原則 | 内容 |
|---|---|
| Zero Telemetry | 製品コードはいかなる目的でも外部サーバーへ通信しません。テレメトリ・解析・クラッシュレポート・利用統計・リモート設定・自動更新ダウンロード・ライセンス認証サーバーのいずれも存在しません。 |
| 完全ローカル処理 | すべての診断・検知・監査はローカルで完結します。URL 安全性診断も秘密情報スキャンも、対象を外部に送信せずヒューリスティックで評価します。 |
| 最小権限 | 特権操作は root デーモンに限定し、UI・CLI・MCP は Unix ドメインソケット越しの IPC で依頼します。TCP/UDP ソケットは一切使用しません。 |
| フェイルクローズド | Air-Gap(緊急遮断)はデーモン再起動をまたいで維持され、外部からルールを消去されても数秒で自動再適用されます。 |
| オフライン・ライセンス | Pro / Business ライセンスは Ed25519 署名の検証のみで完結します。認証サーバーへの問い合わせは発生しません。 |
§2脅威モデル
RoamSwitch for Linux が主に対象とするのは、信頼できないネットワークを渡り歩くラップトップ/モバイルワークステーション です。
想定する攻撃者
- 同一 LAN 上の攻撃者 — 共有 Wi-Fi でのポートスキャン、ARP スプーフィング(中間者攻撃)、誤って
0.0.0.0にバインドされた開発サーバー・ローカル LLM API への不正アクセス。 - 悪意ある USB デバイス(BadUSB) — キーボードを偽装し、画面ロック前にキーストロークを流し込む物理攻撃。
- ランサムウェア/ファイルレスマルウェア — ダウンロードファイル経由で侵入し、ドキュメントを一括暗号化。
- DNS 経由の C2 通信・フィッシング — マルウェアが名前解決で C2 サーバーやフィッシングサイトへ到達。
対象外
- ルート権限を既に奪取した攻撃者。カーネル・ファームウェアレベルのルートキット。
- 物理的にディスクを取り出す攻撃(ディスク暗号化の領域。RoamSwitch は暗号化の有無を診断しますが暗号化自体は行いません)。
- AirDrop 相当の近距離無線共有制御(Linux に OS 標準機構が存在しないため非対応)。
§3コンポーネントと信頼境界
RoamSwitch for Linux は Rust で実装され、6 つのクレートで構成されます。デーモンとの通信はすべて /run/roamswitch/roamswitch.sock(Unix ドメインソケット)を経由します。TCP/UDP のリスニングソケットはどのコンポーネントにも存在しません。アプリが bind するのは二重起動防止用の Unix ソケット 1 つのみです。
# ユーザー空間(非特権)
roamswitch-app GTK3 + AppIndicator トレイ
roamswitch (CLI) シェル用の薄いフロントエンド
roamswitch-mcp stdio JSON-RPC(AI クライアントが起動)
│
│ AF_UNIX /run/roamswitch/roamswitch.sock (ローカル IPC のみ)
▼
roamswitch-daemon root / systemd Type=notify + WatchdogSec=30
・nftables プロファイル制御(inet roamswitch テーブル)
・sentinel ループ(ネットワーク判定・プロファイル適用)
・fanotify ガード / カナリアエンジン / 隔離 Vault
・udev USB 監視(BadUSB) / Ed25519 ライセンス検証
roamswitch-core 純粋ロジックライブラリ(全クレート共通)
roamswitchkit MCP クライアント SDK
| コンポーネント | 権限 | 役割 |
|---|---|---|
| roamswitch-daemon | root(systemd) | すべての特権操作。単一の書き込み者として nftables・DNS・systemd ユニットを制御。 |
| roamswitch-app | ログインユーザー | GTK3 GUI + トレイ。設定編集と可視化のみ。特権操作は IPC 経由。 |
| roamswitch (CLI) | ログインユーザー | シェルからの薄いフロントエンド。同じ IPC ソケットを使用。 |
| roamswitch-mcp | AI クライアントが起動 | stdio JSON-RPC。読み取り専用の診断情報を提供。 |
ユーザー設定は ~/.config/roamswitch/config.json に平文 JSON で保存されます。デーモンは root 権限で /home/*/.config/roamswitch/config.json を走査して読み込みます(デーモンは HOME=/root で動作するため)。設定はマシン外に出ることはなく、アカウント登録もクラウド同期も存在しません。
§4自律ネットワーク防衛
sentinel ループ(既定 5 秒周期)が、デフォルトゲートウェイの MAC アドレスを /proc/net/arp と ip neigh から取得し、config.json の登録済み MAC と照合します。SSID ではなく MAC を用いるのは、SSID が容易に偽装可能であるためです。
| プロファイル | 状況 | nftables の挙動 |
|---|---|---|
| open(信頼) | 登録済みの自宅・社内ネットワーク | policy accept。ローカル通信を許可。 |
| balanced(標準保護) | 未登録だが比較的安全と設定した環境 | 受信をデフォルト拒否。確立済み接続と lo のみ許可。公開ポート露出を監視。 |
| lockdown(外出先保護) | 公衆 Wi-Fi・未登録ネットワーク | 全受信パケットをステルス遮断。共有サービス自動停止(オプトイン)。 |
すべてのルールは inet roamswitch という専用 nftables テーブルに隔離され、他のファイアウォール設定(ufw / firewalld 等)と衝突しません。手動オーバーライドの期限強制(1時間 / 2時間 / 4時間 / 今日いっぱい / 解除まで / 次回切断まで)はデーモンが単一の書き込み者として行います。GUI は期限切れの書き込みを一切行わず、デーモンが書き換えた config.json を次のティックで再読込して UI に反映するだけです(競合回避)。
Air-Gap(緊急ネットワーク遮断)
inet roamswitch テーブルの input・output 両フックに policy drop(優先度 -100)を設定し、lo のみを通す完全遮断モードです。
- フェイルクローズド — デーモン再起動時にマーカーファイル(
/run/roamswitch/airgap.active)を検出すると遮断を再適用。 - 自己修復 — 外部プロセスが
nft delete tableでルールを消去しても、sentinel ループが数秒以内に再適用。 - 自動失効 — 発動から 600 秒(macOS 版の
maxAirGapDurationと同一)で自動的に解除され、誤操作による恒久的なネットワーク喪失を防ぐ。
table inet roamswitch {
chain input {
type filter hook input priority -100; policy <accept|drop>;
iif "lo" accept
ct state established,related accept
# balanced/lockdown: それ以外を drop
}
chain output {
type filter hook output priority -100; policy <accept|drop>;
# Air-Gap 時のみ policy drop、lo と ct established のみ許可
}
}
§5多層マルウェア・ランサムウェア防御
シャノンエントロピー・バースト検知
書き込みイベントを PID 単位 で追跡し、単一プロセスが 3 秒以内にエントロピー 7.85 以上の相異なるファイルを 6 個以上生成した場合にランサムウェアの一括暗号化とみなし、SIGSTOP でプロセスを凍結して Air-Gap を発動します。
- 誤検知対策 —
shred/gpg/ffmpeg/tar/borg/restic/dockerd/qemu等、正当に高エントロピーデータを大量書き込みする約 60 のツールを許可リスト化。同一ファイルの複数回上書き(shredの 3 パス等)は 1 件として数える。 - 重要プロセス保護 —
systemd/dockerd/NetworkManager/sshd/gnome-shell等をハードコードした NEVER_FREEZE リストに照合し、これらは決して凍結しない(マシン全体のハングを防ぐ)。
カナリア(おとりファイル)
ユーザーの Documents / Desktop / Downloads / Pictures および専用ディレクトリにおとりファイルを配置し、SHA-256 ベースラインと 3 秒周期で照合します。改名・削除・切り詰め・内容改変のいずれかを検知すると即座に Air-Gap を発動します。デーモンは root で動作するため、/home/* を走査して実在するユーザー全員のディレクトリにカナリアを展開します。
fanotify 監視・隔離 Vault・ClamAV
- デーモンは
FAN_CLASS_CONTENT(許可モード。不可ならFAN_CLASS_NOTIF)で/home・/var/tmp・/dev/shmをマウント単位、/をファイルシステム単位で監視。 - 検出されたマルウェアは
~/.local/share/roamswitch/quarantine/へ退避。Vault ディレクトリは0700、検体は0400(読み取り専用・実行不可)。復元時はファイルを0644に戻し、元ディレクトリの所有者へ chown。 - ClamAV がある場合、新規ダウンロード実行ファイル(
.sh・.deb・.elf等)と危険な AI モデル(.pkl・.pt)をローカル DB でスキャン。ClamAV は任意の依存で、未インストールでも他の防御は動作。
§6BadUSB 対策
udev の USB イベントを監視し、キーボード(HID)クラスのデバイスを追跡します。
- 既定 ON。インストール後の初回起動ウィザードで、その時点で接続されているキーボードをホワイトリストに登録します。
- 以降、デーモン起動時に接続済みの未登録キーボードは「疑わしい」と扱います(初回接続のデバイスを無条件に信頼はしません)。
- 未登録キーボードの接続を検知するとデスクトップ通知を出し、ユーザーが明示的に許可するまで警告を継続します。
§7セキュリティ健全性診断(20 項目)
roamswitch-core の LinuxHealthChecker が 20 項目を評価し、0〜100 のスコアと A〜F の等級、各項目の改善アドバイスを生成します。GTK ダッシュボード・CLI(roamswitch status)・MCP(get_security_report)のいずれからも、全 20 項目のタイトル・詳細・推奨文が利用者の言語で 表示されます(10 言語対応)。
| 分類 | 項目例 |
|---|---|
| ディスク・ブート | LUKS / dm-crypt 暗号化、UEFI Secure Boot |
| アクセス制御 | LSM(AppArmor / SELinux)、SSH / sudo 設定監査 |
| カーネル堅牢化 | sysctl 強化、コアダンプ制御、/tmp・/dev/shm の noexec |
| 更新 | 自動セキュリティアップデートの設定 |
| ネットワーク | ARP スプーフィング監視、外部公開ポート監査、Wi-Fi 暗号化強度 |
| マルウェア | ClamAV / fanotify / エントロピー監視 / noexec |
| ブラウザ | Firefox / Chrome / Chromium の Safe Browsing 設定 |
| DNS / USB | 脅威保護 DNS(Pro)、USB バスのゼロトラスト状態 |
診断はすべてローカルのファイル・コマンド出力(getenforce・mokutil・resolvectl・ss 等)の読み取りに基づきます。外部への問い合わせは一切ありません。
§8MCP サーバーのセキュリティモデル
roamswitch-mcp は stdio で JSON-RPC を話す MCP サーバーで、Claude Desktop・Cursor・Antigravity 等の AI クライアントから起動されます。提供ツールはすべて 読み取り専用かつローカル完結です。
| ツール | 内容 |
|---|---|
| get_security_report | 20 項目診断・スコア・改善案 |
| get_exposed_ports | 外部公開ポート一覧とファイアウォール遮断状態 |
| get_guard_status | 現在の保護レベルと各防衛モジュールの稼働状況 |
| audit_url_safety | URL のヒューリスティック安全性診断(対象を取得しない) |
| audit_secrets | テキスト中の API キー・秘密情報の検出(テキストを送信しない) |
| audit_security_logs | ローカルの journald / 認証ログの集計 |
| get_quarantine_status / get_canary_status | 隔離・カナリアの状態 |
| get_app_help | 内蔵ナレッジベースの検索 |
MCP サーバーはネットワークを一切使用せず、roamswitchkit 経由でデーモンの Unix ソケットに接続するか、roamswitch-core のロジックを直接呼び出すのみです。
§9データの扱いと Zero Telemetry
lafine systems design は、RoamSwitch for Linux のソースコード全体(v1.0.0、6 クレート)に対して、外部通信の有無を監査しました。
監査方法
- 依存ツリーの検査 —
Cargo.lock全体を、既知の HTTP クライアント(reqwest・hyper・ureq・curl等)、TLS スタック(rustls・native-tls・openssl)、テレメトリ/解析/クラッシュレポート SDK について検索。 - ソースコードの検査 — 全
.rsファイルをTcpStream・TcpListener・UdpSocket・to_socket_addrs・lookup_host・HTTP URL リテラルについて検索。 - サブプロセス呼び出しの列挙 —
Command::new(...)の全呼び出し箇所を確認。
| 監査項目 | 結果 |
|---|---|
| HTTP クライアントライブラリ | 依存ツリーに存在しない |
| TLS スタック | 存在しない |
| テレメトリ/解析/クラッシュレポート SDK | 存在しない |
TcpStream / TcpListener / UdpSocket | ソースコード中に 1 箇所も無し |
| 使用されるソケット API | AF_UNIX(ローカル IPC)のみ |
| ライセンス認証 | Ed25519 署名のオフライン検証。認証サーバー通信なし |
| 自動更新 | ローカルの apt-cache policy を読むのみ。ネットワーク取得は行わない |
RoamSwitch for Linux の製品コードは、いかなる目的でも外部サーバーへ通信を開始しません。
外部に触れる動作の全リスト(例外の完全な列挙)
透明性のため、間接的にでもパケットがローカルマシン外へ出る可能性のある動作をすべて列挙します。いずれも RoamSwitch 自身が HTTP リクエストを送るものではなく、ユーザーの明示的操作か OS 既存機構の設定変更です。
| # | 動作 | 発生条件 | 送信内容 |
|---|---|---|---|
| 1 | ping -c1 -W1 <gw> | ARP スプーフィング検知時に ARP キャッシュを更新するため。宛先は LAN のデフォルトゲートウェイのみ | ICMP エコー要求のみ。DNS 解決なし、ペイロードなし |
| 2 | システムブラウザの起動(xdg-open) | 「リリースノートを開く」等のボタンをユーザーが押した時のみ | RoamSwitch プロセスはソケットを開かない。URL を OS のブラウザに渡すだけ |
| 3 | freshclam | GUI の「ウイルス定義を今すぐ更新」をユーザーが押した時のみ。自動・定期実行は一切しない | ClamAV 本体(別プロジェクト)の通信。RoamSwitch は起動するだけ |
| 4 | resolvectl dns … | 未信頼ネットワークでの脅威保護 DNS(Pro・オプトイン) | OS のリゾルバ設定を変更するのみ。RoamSwitch 自身は DNS クエリを送らない |
| 5 | パッケージマネージャによる更新 | ユーザーが apt upgrade 等を実行した時 | RoamSwitch はローカルの apt-cache policy を読むのみ。ネットワーク取得を起動しない |
上記以外の RoamSwitch のすべての機能(nftables 制御、ポートスキャン、ARP 監視、健全性診断、エントロピー監視、カナリア、fanotify、USB 監視、隔離、ログ監査、URL・秘密情報の監査)は ローカルのファイル読み取りとサブプロセス出力の解析のみ で完結します。
Mac の中に残るもの(プライバシー)
- アカウント不要 — ユーザー登録・ログイン・メールアドレスの入力は一切なし。
- 設定はローカルのみ —
~/.config/roamswitch/config.jsonに平文で保存、マシン外に出ない。クラウド同期なし。 - 診断結果はローカルのみ — 画面表示と、ユーザーが選べばローカルファイルへのエクスポートのみ。
- ライセンスキーはオフライン検証 — Ed25519 署名を公開鍵で検証。lafine のサーバーへ問い合わせない。
- クラッシュレポートなし — パニック時もスタックトレースを外部送信しない。
§10ライセンスと配布
| エディション | 対象 | 価格 | ライセンス |
|---|---|---|---|
| Community Edition | Linux 個人利用 | 無料 | プロプライエタリ・フリーウェア(同梱の EULA) |
| Business(予定) | 組織での集中管理・ポリシー配布・署名済み内部 apt・SLA | 有償 | 商用ライセンス。同一バイナリ+ティアゲート方式 |
macOS 版 Pro Lifetime 購入者には、本人の Linux マシンにおける Business 機能を無償付与します。
配布とサプライチェーン
| 経路 | 内容 |
|---|---|
| APT | https://lafine.net/apt(stable main)。RSA-4096 鍵で Release を署名 |
| RPM | https://lafine.net/rpm(Fedora / openSUSE 別)。repomd.xml を GPG 署名 |
| AUR | roamswitch-bin(GitHub Releases の tarball を取得、sha256 検証) |
| tarball | GitHub Releases に amd64 / aarch64 の .tar.gz + .sha256 |
- glibc 下限の固定 — リリースバイナリは Debian 12(bookworm、glibc 2.36)のコンテナ内でビルドされ、Debian 12 / Ubuntu 22.04 以降でシンボルバージョン不整合が起きない。CI に「glibc フロア検証」ステップを設ける。
- 署名鍵の管理 — リポジトリ署名の秘密鍵は GitHub Actions の暗号化シークレットにのみ存在し、リポジトリには公開鍵のみをコミットする。
§11動作環境
- OS: Ubuntu 22.04 / 24.04 以降、Debian 12 以降、Linux Mint / Pop!_OS / elementary / Zorin、Raspberry Pi OS 64bit(Bookworm)、Ubuntu for Raspberry Pi
- アーキテクチャ: x86_64 / aarch64
- 必須:
systemd、nftables(パッケージ依存で自動導入) - 任意:
clamav(マルウェアスキャン)、nmcli(Wi-Fi 暗号化判定)、libnotify(デスクトップ通知) - 非対応: 非 systemd 系(Alpine / Void / Devuan)
- 画面: 1280×720 以上(画面サイズに応じてウィンドウとフォントを自動スケール。Raspberry Pi の小型ディスプレイに対応)
§12直接依存クレート
| クレート | 用途 | ネットワーク |
|---|---|---|
| serde / serde_json | 設定・IPC のシリアライズ | なし |
| tokio | 非同期ランタイム(使用は Unix ソケットのみ) | なし(TCP 未使用) |
| tracing | ログ出力(ローカル・journald) | なし |
| url | URL のパース(診断ヒューリスティック) | なし(取得しない) |
| ed25519-dalek | ライセンス署名のオフライン検証 | なし |
| base64 / sha2 | ライセンストークン・カナリアのハッシュ | なし |
| libc | chown / kill / システムコール | なし |
| open | 「リリースノートを開く」で xdg-open を呼ぶ | プロセス自体は通信しない |
| GTK3 / ksni(app のみ) | GUI とトレイ | なし |
依存ツリー全体に HTTP クライアント・TLS スタック・テレメトリ SDK は存在しません。
付録 Aセルフチェック(自分で検証する)
本書の主張は、いずれも利用者自身の手元で確認できます。以下は roamswitch をインストールした環境で実行できます。
A.1 「外部送信データゼロ」を自分で確かめる
依存ツリー(ソースツリーで、HTTP クライアント・TLS・テレメトリ SDK が無いこと):
grep -iE '^name = "(reqwest|hyper|ureq|curl|rustls|native-tls|openssl|sentry|opentelemetry)"' Cargo.lock
# → 出力なし = 依存ツリーに存在しない
ソースコード(TCP/UDP ソケットが無いこと):
grep -rn 'TcpStream\|TcpListener\|UdpSocket\|to_socket_addrs' crates/*/src --include='*.rs'
# → 出力なし。使われるソケットは AF_UNIX のみ
稼働中のデーモン(インターネットソケットを 1 つも開いていないこと):
sudo lsof -p "$(pgrep -x roamswitch-daemon)" -a -i
# → 出力なし = TCP/UDP のインターネット接続はゼロ
watch -n 5 'sudo ss -tupn | grep roamswitch || echo "(no external sockets)"'
# → 常に "(no external sockets)"
A.2 破壊的セルフテストスイート
test/docker/ に、破壊的テストを隔離実行する使い捨て --privileged コンテナ(独立したネットワーク名前空間。Air-Gap がホストを切断しない)が同梱されています。Debian 12(リリース CI と同じ glibc 下限)でソースからビルドし、デーモンを起動して以下を順に検証します。
docker build -t roamswitch-test -f test/docker/Dockerfile .
docker run --rm --privileged roamswitch-test
| ID | シナリオ | 判定基準 |
|---|---|---|
| SP-1 | ランサムウェアおとり(カナリア)改ざん検知 | 数秒以内に「Canary tampered」を検知し Air-Gap 発動 |
| SP-2 | ランサムウェア一括暗号化のバースト検知 | 当該プロセスを SIGSTOP で凍結し Air-Gap 発動 |
| SP-2b | shred 誤検知の非発生 | 「RANSOMWARE BURST」が出ないこと(許可リスト) |
| SP-2c | 重要プロセスの非凍結 | dockerd 等の重要プロセスを凍結しないこと |
| SP-3 | Air-Gap 有効化 → 遮断 | output フックに policy drop が入り、外部通信が不可になる |
| SP-3b | Air-Gap の自己修復 | 外部から nft delete table → sentinel ループが 5 秒以内に再適用 |
| SP-3c | Air-Gap のフェイルクローズド | Air-Gap 中にデーモン再起動 → 遮断が維持される |
| SP-3d | Air-Gap 解除 → 復旧 | drop ポリシー解除、全マーカーファイル削除、通信復旧 |
| SP-4 | マルウェア隔離(EICAR) | Downloads から消え、隔離 Vault へ退避される |
| SP-4b | 隔離 Vault の権限堅牢化 | ディレクトリ 0700、検体 0400 |
実機(ext4 の ~/)で追加検証(コンテナの overlayfs / tmpfs では fanotify イベントが配送されないため): SP-2 実機(python3 による 6 ファイル以上のバースト → 凍結 → Air-Gap)、SP-1 実機(監視カナリア 16 個の rename を約 2 秒で検知)、SP-5(MCP get_guard_status の手動オーバーライドラベル整合性)、SP-6(BadUSB:起動時に接続済みの未登録キーボードを「疑わしい」と扱う)、CLI 全サブコマンド(status / guards / wifi / ports / canary / quarantine / audit-url / audit-secrets / audit-logs / knowledge / sharing)の日英動作確認。
A.3 直近の実行結果
Docker セルフテスト(roamswitch-test イメージ): 14 / 15 PASS。唯一の非 PASS は SP-2(コンテナ内エントロピーバースト)で、コンテナの overlayfs / tmpfs では fanotify の許可イベントがカーネルから配送されないという既知の制約によります。ハーネスは fanotify 配送プローブでこれを自動判定し、配送不可の環境では FAIL ではなく SKIP とし、実機(ext4 の ~/)で別途 PASS を確認しています。
セルフペンテストで発見された不具合(カナリアの $HOME 相対パス誤り、MCP の serde camelCase 不整合、disable_air_gap の再適用漏れ、隔離 Vault の過剰なパーミッション、shred の誤検知、Docker デーモンの誤凍結)はすべて修正し、再検証済みです。
A.4 既知の制約
| 制約 | 影響 | 対応 |
|---|---|---|
一部カーネルで tmpfs(/tmp)への FAN_MARK_MOUNT がイベントを配送しない | /tmp のファイル書き込みは fanotify で監視されない | /tmp は揮発性かつ監視対象ユーザーフォルダではない。ランサムウェアの標的は ~/。マーク失敗時はログに明示 |
| コンテナ overlayfs / tmpfs での fanotify 非配送 | Docker 内でのエントロピーバースト検知が検証不可 | 実機(ext4)で検証。ハーネスがプローブで自動 SKIP |
RoamSwitch の nftables 操作と Docker の iptables-nft が同一 netfilter 空間を共有 | RoamSwitch のルール操作が Docker の NAT ルールと干渉し得る | 運用上の注意点として文書化。専用テーブル inet roamswitch で分離するが、nft flush ruleset 等の全体操作は避ける |