Lafine Systems Design · 技術文書

RoamSwitch for Linux アーキテクチャ/セキュリティホワイトペーパー

RoamSwitch for Linux がどのような権限で動作し、その境界で何を行っているのかを説明する技術文書です。宣伝的な表現は使わず、記載した内容はすべて、配布中のソースおよび実際の動作から確認できるようにしています。

v1.0 対象 RoamSwitch for Linux 1.0 要件 systemd + nftables 発行 2026-09-02

§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-daemonroot(systemd)すべての特権操作。単一の書き込み者として nftables・DNS・systemd ユニットを制御。
roamswitch-appログインユーザーGTK3 GUI + トレイ。設定編集と可視化のみ。特権操作は IPC 経由。
roamswitch (CLI)ログインユーザーシェルからの薄いフロントエンド。同じ IPC ソケットを使用。
roamswitch-mcpAI クライアントが起動stdio JSON-RPC。読み取り専用の診断情報を提供。

ユーザー設定は ~/.config/roamswitch/config.json に平文 JSON で保存されます。デーモンは root 権限で /home/*/.config/roamswitch/config.json を走査して読み込みます(デーモンは HOME=/root で動作するため)。設定はマシン外に出ることはなく、アカウント登録もクラウド同期も存在しません。

§4自律ネットワーク防衛

sentinel ループ(既定 5 秒周期)が、デフォルトゲートウェイの MAC アドレスを /proc/net/arpip 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-coreLinuxHealthChecker が 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 バスのゼロトラスト状態

診断はすべてローカルのファイル・コマンド出力(getenforcemokutilresolvectlss 等)の読み取りに基づきます。外部への問い合わせは一切ありません。

§8MCP サーバーのセキュリティモデル

roamswitch-mcp は stdio で JSON-RPC を話す MCP サーバーで、Claude Desktop・Cursor・Antigravity 等の AI クライアントから起動されます。提供ツールはすべて 読み取り専用かつローカル完結です。

公開ツール
ツール内容
get_security_report20 項目診断・スコア・改善案
get_exposed_ports外部公開ポート一覧とファイアウォール遮断状態
get_guard_status現在の保護レベルと各防衛モジュールの稼働状況
audit_url_safetyURL のヒューリスティック安全性診断(対象を取得しない)
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 クレート)に対して、外部通信の有無を監査しました。

監査方法

  1. 依存ツリーの検査Cargo.lock 全体を、既知の HTTP クライアント(reqwesthyperureqcurl 等)、TLS スタック(rustlsnative-tlsopenssl)、テレメトリ/解析/クラッシュレポート SDK について検索。
  2. ソースコードの検査 — 全 .rs ファイルを TcpStreamTcpListenerUdpSocketto_socket_addrslookup_host・HTTP URL リテラルについて検索。
  3. サブプロセス呼び出しの列挙Command::new(...) の全呼び出し箇所を確認。
監査結果
監査項目結果
HTTP クライアントライブラリ依存ツリーに存在しない
TLS スタック存在しない
テレメトリ/解析/クラッシュレポート SDK存在しない
TcpStream / TcpListener / UdpSocketソースコード中に 1 箇所も無し
使用されるソケット APIAF_UNIX(ローカル IPC)のみ
ライセンス認証Ed25519 署名のオフライン検証。認証サーバー通信なし
自動更新ローカルの apt-cache policy を読むのみ。ネットワーク取得は行わない
結論

RoamSwitch for Linux の製品コードは、いかなる目的でも外部サーバーへ通信を開始しません。

外部に触れる動作の全リスト(例外の完全な列挙)

透明性のため、間接的にでもパケットがローカルマシン外へ出る可能性のある動作をすべて列挙します。いずれも RoamSwitch 自身が HTTP リクエストを送るものではなく、ユーザーの明示的操作か OS 既存機構の設定変更です。

#動作発生条件送信内容
1ping -c1 -W1 <gw>ARP スプーフィング検知時に ARP キャッシュを更新するため。宛先は LAN のデフォルトゲートウェイのみICMP エコー要求のみ。DNS 解決なし、ペイロードなし
2システムブラウザの起動(xdg-open「リリースノートを開く」等のボタンをユーザーが押した時のみRoamSwitch プロセスはソケットを開かない。URL を OS のブラウザに渡すだけ
3freshclamGUI の「ウイルス定義を今すぐ更新」をユーザーが押した時のみ。自動・定期実行は一切しないClamAV 本体(別プロジェクト)の通信。RoamSwitch は起動するだけ
4resolvectl 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 EditionLinux 個人利用無料プロプライエタリ・フリーウェア(同梱の EULA)
Business(予定)組織での集中管理・ポリシー配布・署名済み内部 apt・SLA有償商用ライセンス。同一バイナリ+ティアゲート方式

macOS 版 Pro Lifetime 購入者には、本人の Linux マシンにおける Business 機能を無償付与します。

配布とサプライチェーン

経路内容
APThttps://lafine.net/aptstable main)。RSA-4096 鍵で Release を署名
RPMhttps://lafine.net/rpm(Fedora / openSUSE 別)。repomd.xml を GPG 署名
AURroamswitch-bin(GitHub Releases の tarball を取得、sha256 検証)
tarballGitHub 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
  • 必須: systemdnftables(パッケージ依存で自動導入)
  • 任意: clamav(マルウェアスキャン)、nmcli(Wi-Fi 暗号化判定)、libnotify(デスクトップ通知)
  • 非対応: 非 systemd 系(Alpine / Void / Devuan)
  • 画面: 1280×720 以上(画面サイズに応じてウィンドウとフォントを自動スケール。Raspberry Pi の小型ディスプレイに対応)

§12直接依存クレート

クレート用途ネットワーク
serde / serde_json設定・IPC のシリアライズなし
tokio非同期ランタイム(使用は Unix ソケットのみ)なし(TCP 未使用)
tracingログ出力(ローカル・journald)なし
urlURL のパース(診断ヒューリスティック)なし(取得しない)
ed25519-dalekライセンス署名のオフライン検証なし
base64 / sha2ライセンストークン・カナリアのハッシュなし
libcchown / 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-2bshred 誤検知の非発生「RANSOMWARE BURST」が出ないこと(許可リスト)
SP-2c重要プロセスの非凍結dockerd 等の重要プロセスを凍結しないこと
SP-3Air-Gap 有効化 → 遮断output フックに policy drop が入り、外部通信が不可になる
SP-3bAir-Gap の自己修復外部から nft delete table → sentinel ループが 5 秒以内に再適用
SP-3cAir-Gap のフェイルクローズドAir-Gap 中にデーモン再起動 → 遮断が維持される
SP-3dAir-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 等の全体操作は避ける
この文書は RoamSwitch for Linux v1.0 時点の実装に基づきます。最新情報は lafine.net/linux を参照してください。