Lafine Systems Design · 技術文書

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

RoamSwitch for Linux がどのような権限で動作し、その境界で何を行っているのかを説明する技術文書です。宣伝的な表現は使わず、記載内容は配布パッケージの実際の動作と、本書付録のセルフチェックで確認できるようにしています。

v1.6.0 対象 RoamSwitch for Linux 1.1.0(カーネル LPE 堅牢化/eBPF ランタイム防護/攻撃プロセス SIGSTOP 凍結/Falco 低負荷最適化) 要件 systemd + nftables 発行 2026-09-06

§1概要

RoamSwitch for Linux は、macOS 版 RoamSwitch のゼロトラスト・ネットワーク防衛思想を Linux(systemd + nftables 環境)向けに完全実装した、常駐型のネットワークセキュリティ&システム診断ソフトウェアです。

本エディションはクライアント端末(ワークステーション・ラップトップ・シングルボード)向けであり、ネットワーク移動に追従してプロファイルを切り替える自律動作を前提とします。サーバー/ヘッドレス基盤向けの強化版(既定拒否を基本とし、公開するサービスポートだけを明示許可してインバウンドを最小化、外向き通信も制限。ネットワーク移動への自律追従はせず、静的な署名付きポリシーとリモート管理・監査で運用)は別途、専用の RoamSwitch Server Edition として提供されます。

接続中の Wi-Fi / 有線ネットワークをゲートウェイ MAC アドレス単位で識別し、nftables のファイアウォールプロファイルを自律的に切り替えます。加えて、未信頼ネットワークでの中間者攻撃(MITM)対策を 3 層で提供します——VPN トンネル + キルスイッチ(WireGuard または Tailscale、本命)、予防的 ARP/NDP ロックARP スプーフィング検知。さらにランサムウェアの挙動検知(fanotify + シャノンエントロピー + カナリア)、フィッシング接続を警告・遮断する受動リンクガード(NFQUEUE + SNI)、ポート異常ガード、BadUSB 対策、カーネル特権昇格(LPE)の予防的封鎖(Frag Gap CVE-2026-53362 対策)eBPF ランタイム脅威センサー(Falco / Tetragon)連携による攻撃プロセスのミリ秒凍結(SIGSTOP)と自動 Air-Gap 隔離、24 項目のセキュリティ健全性診断、Model Context Protocol(MCP)サーバーを標準搭載します。

本書は、アーキテクチャ・脅威モデル・各防衛機構の設計、そして 「完全ローカル処理。マシン外へ出るのは署名付き検出データの要求だけで、そこに利用者の情報は一切含まれない」 というプライバシー原則がどのようにコードレベルで担保されているかを説明します。宣伝的な表現は避け、記載内容は配布パッケージ(バイナリ)の実際の動作と、本書付録のセルフチェックで確認できるようにしています。RoamSwitch for Linux はプロプライエタリ・フリーウェアで、ソースコードは公開していません(§11)。

設計原則
原則内容
Zero Telemetry製品は利用者・端末に関する情報を一切外部へ送信しません。テレメトリ・解析・クラッシュレポート・利用統計・リモート設定・ライセンス認証サーバーのいずれも存在しません。
受信専用の更新製品が行う唯一の外向き通信は、1 日 1 回、固定 URL(lafine.net/updates/v1)の署名付きマニフェストを GET することだけです。取得するのはリンクガードの詐欺サイト一覧・ClamAV 定義バージョン・本体の最新バージョン。クエリ文字列・Cookie・識別ヘッダはなく、利用者に関する情報は一切含まれません。updates.enabled = false で完全に停止し、その場合は同梱データのみで動作し外部接触はゼロになります。
完全ローカル処理すべての診断・検知・監査はローカルで完結します。URL 安全性診断も秘密情報スキャンも、対象を外部に送信せずヒューリスティックで評価します。
最小権限特権操作は root デーモンに限定し、UI・CLI・MCP は Unix ドメインソケット越しの IPC で依頼します。デーモンは TCP/UDP ソケットを開きません。リンクガードは AF_NETLINK の NFQUEUE verdict チャネル(カーネル ↔ ユーザー空間、パケット送出なし)のみを使用します。
フェイルクローズドAir-Gap(緊急遮断)はデーモン再起動をまたいで維持され、外部からルールを消去されても数秒で自動再適用されます。
オフライン・ライセンスPro / Business ライセンスは Ed25519 署名の検証のみで完結します。認証サーバーへの問い合わせは発生しません。

§2脅威モデル

RoamSwitch for Linux が主に対象とするのは、信頼できないネットワークを渡り歩くラップトップ/モバイルワークステーション です。

想定する攻撃者

  • 同一 LAN 上の攻撃者 — 共有 Wi-Fi でのポートスキャン、ARP/NDP スプーフィング(不正 RA を含む)による中間者攻撃、不正 DHCP、MAC フラッディング後の受動盗聴、誤って 0.0.0.0 にバインドされた開発サーバー・ローカル LLM API への不正アクセス。
  • 悪意ある USB デバイス(BadUSB) — キーボードを偽装し画面ロック前にキーストロークを流し込む物理攻撃。未承認 USB マスストレージによるデータ持ち出し・マルウェア持ち込み。
  • ランサムウェア/ファイルレスマルウェア — ダウンロードファイル経由で侵入し、ドキュメントを一括暗号化。
  • DNS 経由の C2 通信・フィッシング — マルウェアが名前解決で C2 サーバーやフィッシングサイトへ到達。

対象外

  • ルート権限を既に奪取した攻撃者。カーネル・ファームウェアレベルのルートキット。
  • 物理的にディスクを取り出す攻撃(ディスク暗号化の領域。RoamSwitch は暗号化の有無を診断しますが暗号化自体は行いません)。
  • AirDrop 相当の近距離無線共有制御(Linux に OS 標準機構が存在しないため非対応)。

§3システムアーキテクチャ

RoamSwitch for Linux は Rust で実装され、7 つのクレートで構成されます。デーモンとの通信はすべて /run/roamswitch/roamswitch.sock(Unix ドメインソケット)を経由します。TCP/UDP のリスニングソケットはデーモン・アプリ・MCP のいずれにも存在しません。アプリが 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 ループ(ネットワーク判定・プロファイル適用)
  ・VPN トンネル + キルスイッチ(WireGuard: wg-quick / roamswitch_vpn、Tailscale: roamswitch_ts)
  ・予防的 ARP/NDP ロック(neigh テーブル固定) / 検知
  ・ポート異常ガード(roamswitch_dev_guard)
  ・fanotify ガード(ランサムウェア/マルウェア)
  ・リンクガード(NFQUEUE — inet roamswitch_linkguard)
  ・カナリアエンジン / 隔離 Vault
  ・カーネル LPE 堅牢化(userns 無効化・Yama LSM)
  ・eBPF ランタイム連携(/var/run/roamswitch/events.sock)
  ・攻撃プロセスのミリ秒 SIGSTOP 凍結 & Air-Gap 連動
  ・USB 監視(evdev EVIOCGRAB — BadUSB) / 承認キュー
  ・Ed25519 ライセンス検証

roamswitch-updater  単独の systemd タイマー ヘルパー。HTTP/TLS スタックを
                    持つ唯一のクレート(日次の署名付きマニフェスト GET)
roamswitch-core     純粋ロジックライブラリ(全クレート共通)
roamswitchkit       MCP クライアント SDK
特権分離
コンポーネント権限役割
roamswitch-daemonroot(systemd、Type=notify + WatchdogSec=30すべての特権操作。単一の書き込み者として nftables・DNS・systemd ユニットを制御。
roamswitch-appログインユーザーGTK3 GUI + AppIndicator トレイ。設定編集と可視化のみ。特権操作はすべて IPC 経由。
roamswitch (CLI)ログインユーザーシェルからの薄いフロントエンド。同じ IPC ソケットを使用。
roamswitch-mcpAI クライアントが起動するプロセスstdio JSON-RPC。読み取り専用の診断情報を提供。

デーモンとの通信はすべて /run/roamswitch/roamswitch.sock0700 相当のディレクトリ権限)を経由します。ユーザー設定は ~/.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 のみ許可
    }
}

受動リンクガード(フィッシング接続の検知)

デーモンが外向き接続の接続先を監視し、危険なホストへの接続を警告します(狭義の「明らかなフィッシング」に該当する場合は遮断します)。従来の「URL を貼り付けて診断する」機能——ユーザーの操作を要した——を置き換えます。

  • 傍受 — 専用の nftables テーブル inet roamswitch_linkguardoutput フックにかかり、DNS 質問と新規/初期の Web 接続を NFQUEUE 経由でユーザー空間ワーカーへ送ります。NFQUEUE は AF_NETLINK 上のカーネル ↔ ユーザー空間 verdict チャネルであり、デーモンはソケットを bind せずパケットも発生させません。キュー規則には bypass が付いており、ワーカーが動作していない場合は通信がそのまま通ります(Air-Gap が別の hard stop)。
  • ホスト名の取得元 — DNS 質問名、TLS ClientHello の SNI(DoH を使うブラウザでもホスト名は把握できる)、平文 HTTP の Host ヘッダ。ECH(Encrypted ClientHello)が普及した場合はそのホストが盲点になります(既知の限界)。
  • 判定roamswitch-core の純ロジック)— ホストをローカルのフィッシング/脅威フィードと、オフラインのヒューリスティック(保護ブランドの IDN/混同ホモグラフ、非公式ドメインに含まれるブランド名、IP 直打ち、高リスク TLD)に照らします。
モード(linkGuard.modeフィード命中 or ブランドのホモグラフその他の疑わしいシグナル
off検査しない検査しない
warn接続を最大 8 秒保留 + 許可/ブロックの承認通知通知のみ
block(既定)接続を遮断 + 許可ダイアログ(ホスト単位に 1 回)通知のみ

hard-block されるのはフィード命中またはブランドのホモグラフのホストだけで、ヒューリスティック単体が拾ったものはすべて警告に留まります。warn モードは危険なホストへの接続を 最大 8 秒保留 してユーザーに諮り、無応答のまま保留が切れた場合は fail-closed(パケットを drop、判定はキャッシュしない)——「確認に無応答」を「許可」とみなしません。次回アクセスで再度確認します。block モードでもホスト単位に 1 回だけ通知+許可ダイアログを表示します(同じホストへのブラウザの多数の接続で通知が氾濫しない)。危険な対象の承認ダイアログは既定ボタンが「遮断を維持」で、「許可」は目立たない配色です。遮断されたホストは通知から恒久的または 5 分間だけ許可できます(linkGuard.allowlist)。

DNS は検査するが偽造しない: ブロックリストに載った DNS 質問は通知のみを生成し、強制は後続の TCP 接続で行います。RoamSwitch が偽の DNS 応答を注入することはありません。フィードはフィッシング/詐欺ドメインをコンパイルした一覧で、パッケージに同梱され、日次アップデータ(§11)で更新されます。フィードが無くてもオフラインのヒューリスティックは動作します。フィードファイルの Ed25519 署名は読み込み前に検証され、不正・欠落時は「ヒューリスティックのみ」にフェイルクローズドします(「すべて許可」にはなりません)。

VPN トンネル + キルスイッチ(MITM 対策の本命)

L2 の完全性に依存しない中間者攻撃対策。未信頼ネットワークでは、信頼できるエンドポイントへの常時暗号化トンネルを張ることで、ローカルの ARP/NDP スプーフィング・不正 DHCP・受動盗聴をすべて無意味化します——攻撃者に見えるのは暗号文だけです。下記の ARP/NDP 固定と検知は、この機能の補助という位置づけです。

バックエンドは 2 つから選べます——「WireGuard(設定ファイル)」または「Tailscale(Exit Node)」。RoamSwitch 自身は暗号処理を実装せず、VPN 事業者にもなりません。いずれも任意依存で、未導入なら GUI が導入方法を案内します。

(A) WireGuard バックエンド

  • VPN サーバーは提供しない — ユーザーが用意した WireGuard 設定を使います。Mullvad・IVPN・Proton VPN など WireGuard 対応プロバイダーの .conf、または自前の WireGuard サーバー(VPS・自宅サーバー)を想定。同梱のデフォルト設定はありません。
  • 設定 — 標準の .conf を読み込み、デーモンが検証して /etc/wireguard/roamswitch.conf0600、IF 名 roamswitch)に保存。/etc/wireguard/ 以外に置けないのは、Ubuntu 24.04+ / Debian 13 の AppArmor wg-quick プロファイルがそれ以外の .conf 読み取りを(root でも)拒否するためです。AllowedIPs0.0.0.0/0::/0)でないスプリットトンネルは「全通信は保護されない」と警告します。
  • キルスイッチ — 専用 nftables テーブル inet roamswitch_vpnpolicy drop、両フック)が ループバック・トンネル IF(roamswitchoifname 名照合)・固定したエンドポイント IP への UDP・DHCP・ICMP 以外をすべて遮断します。トンネルを張るに(エンドポイントを getent ahosts で固定 IP に解決してから)設置されるため漏洩ウィンドウがありません。wg-quick up が失敗してもキルスイッチは維持されます。

(B) Tailscale バックエンド

  • 既に Tailscale を使っているユーザー向け。RoamSwitch は tailscale up / ログイン / tailscaled の導入は行いません——tailscale status --json を読み、tailscale set --exit-node=<ノード> /(解除)を実行するだけです。
  • Exit Node 必須 — 中間者攻撃対策は「全通信を経由させる Exit Node」の指定で初めて成立します。指定が無い場合は保護を有効化せず「保護されていません」と警告します。選択したノードがオフラインになった場合は保護を自動解除して通知します(死んだノードへ全通信を流すブラックホールを避けるため)。
  • キルスイッチinet roamswitch_tspolicy drop) — Tailscale のトランスポートは単一エンドポイント IP に固定できない(DERP リレー・NAT 越えでピアのアドレスが動く)ため WireGuard よりゆるめです。許可するのは: ループバック、トンネル IF(tailscale0)、CGNAT レンジ 100.64.0.0/10fd7a:115c:a1e0::/48、STUN(udp/3478)、DERP(tcp/443)、udp/41641、DHCP、ICMP、MagicDNS(100.100.100.100:53)、確立済み接続。それ以外(任意 UDP、ローカルリゾルバへの DNS、SMB、mDNS、平文 HTTP、任意 TCP)は全遮断します。
  • 既知の限界 — (1) WireGuard バックエンドより許可範囲が広い(udp/3478tcp/443・CGNAT /10 全体)。(2) 経路上の攻撃者はメタデータ(Tailscale 利用の事実、DERP リージョン、タイミング)を観測でき、遮断・遅延も可能——ただしトンネル内容は読めません。(3) 直結 UDP 遮断時の機密性は Tailscale 自身の DERP TLS(証明書ピン)に依存します。(4) MagicDNS オフかつローカルリゾルバ利用時は、キルスイッチ有効中に DNS が引けなくなります(GUI で警告)。(5) キャプティブポータルは有効化前にログインが必要です。

共通vpn_on_untrusted_enabled かつ未信頼(level != open)のときのみ作動。信頼済みネットワークでは Exit Node をクリアしキルスイッチを撤去します(tailscale down はしません)。既定 OFF・オプトイン。外向き通信の宛先は WireGuard/Tailscale ともにユーザー自身の VPN エンドポイント/tailnet であり、lafine のインフラとは無関係です(§9)。

予防的 ARP/NDP ロック

未信頼ネットワークに接続した時点で、中間者攻撃の攻撃者が「なりすます」必要のある同一リンク上のインフラ機器の MAC アドレスをカーネルの neigh テーブルに PERMANENT(静的)エントリとして固定します。固定後はカーネルが偽の ARP 応答/近隣広告を無視するため、攻撃者は poisoning を成立させられません。

  • 固定対象 — (1) IPv4 デフォルトゲートウェイ、(2) IPv6 デフォルトルーター(多くは fe80:: リンクローカル)、(3) 同一リンク上の DNS リゾルバ(公開リゾルバはゲートウェイ経由のため対象外)。IPv6 は ip -6 neigh replace ... nud permanent で NDP エントリを固定します。
  • 信頼済みネットワークでは固定しません——自宅ルーターの再起動で通信不能になることを防ぐため。ネットワーク切替のたびに固定し直します(TOFU)。正規のフェイルオーバーは次回の再接続で追従します。固定エントリは /var/lib/roamswitch/arp_lock.json に記録され、確実に解除されます。
  • 既定 ON(Community Edition の方針。macOS Pro 版と同じ内訳)。設定 gateway_arp_lock_enabled

ARP スプーフィング検知(notify-first)

/proc/net/arp を監視し、同一 IP に複数の MAC が対応する状態、およびゲートウェイ MAC の不審な急変を検知します。lockdown 中は通信を全遮断(Air-Gap)+通知。balanced/信頼済みネットワークではいきなり遮断せず通知のみを出し、ユーザーが RoamSwitch から緊急遮断を実行できます。これは、(a) 攻撃者が偽の ARP パケット 1 つでユーザーを自らオフラインにさせる DoS を防ぎ、(b) ルーター再起動・アクセスポイントのローミングでの誤発動を防ぐためです。設定 arp_spoof_guard_enabled

ポート異常ガード

新たに外部 LAN に公開されたリスニングポート(バックドア・C2・誤って 0.0.0.0 にバインドされた開発サーバー/ローカル LLM API)を自動的に隔離します。「危険なポート番号」ではなく ベースライン相対 で判定します。有効化した時点で外部公開中の実行体を「既知」として学習し、以後新規に現れた公開実行体のみをフラグします(アイデンティティは実行体パス、snap は snap:<name> に正規化)。システムデーモンは対象外。隔離は inet roamswitch_dev_guard テーブルで「lo 以外からの当該 TCP ポート宛を drop」——マシン自身からの利用は継続可能。隔離時は即座にデスクトップ警告通知と確認ダイアログ(「このポートを許可する」「遮断を維持する」)を表示し、ワンクリックで恒久許可リストに登録できます。ポート診断画面からも個別許可・ベースライン再取得ができます。既定 ON。設定 port_anomaly_guard_enabled。macOS 版から移植。

Docker リスク検知 & ファイアウォール迂回対策

Docker の公開ポート(-p)はホストの標準ファイアウォールをバイパスする既知の問題があるため、DOCKER-USER チェーンに検査ルールを常時挿入し、許可されていない外部トラフィックを遮断します(設定不要、既定で常時有効)。加えて、--privileged コンテナの起動や /var/run/docker.sock のマウント(コンテナ脱出リスク)を docker events でリアルタイム検知し、検知した瞬間に通知します。リスクの高い設定であって確認された侵害ではないため、自動遮断は行わない通知専用です。

機密情報・APIキー漏洩スキャナ

OpenAI・Anthropic・AWS・GitHub・Slack・Stripe 等の API キーや SSH 秘密鍵をシャノンエントロピーとパターンマッチで検出します。roamswitch audit-secrets <text|ファイル|ディレクトリ> でテキスト・ファイルに加え、ディレクトリを再帰的にスキャン可能(.gitnode_modules 等は自動除外、2MB 超・バイナリファイルはスキップ)。MCP ツール(audit_secrets)・Python SDK(audit_secrets_directory())からも同じ機能を呼び出せます。内容が外部へ送信されることはありません。

初回セットアップ ウィザードと確認 UI

パッケージが /etc/xdg/autostart/roamswitch.desktop を同梱し、インストール後の次回ログインでセットアップ ウィザードが自動起動します(完了後はトレイ常駐のみ)。セキュリティガードの有効化・無効化には、macOS 版と同じ対象(ポート異常・ARP 自動遮断・USB ストレージ・BadUSB キーボード・Bluetooth)で確認ダイアログを表示します。イベント発生時の判断(不明な USB キーボード、未登録 USB メモリ、未知ポートの自動遮断、緊急遮断)はモーダルダイアログとして提示されます。

§5多層マルウェア・ランサムウェア防御

シャノンエントロピー・バースト検知と YARA スキャン

書き込みイベントを PID 単位 で追跡し、単一プロセスが 5 秒以内にエントロピー 7.92 以上の相異なるファイルを 20 個以上生成した場合にランサムウェアの一括暗号化とみなし、SIGSTOP でプロセスを凍結して Air-Gap を発動します。

  • YARA スキャンとエントロピー検知の完全分離 — YARA マルウェア検知は ~/.cache/node_modules/、各種アーカイブを含め、すべての書き込みファイルに対して漏れなく実行します(ゼロバイパス)。一方、エントロピー暗号化バースト判定からは、最初から圧縮されている形式(.zip, .tgz, .tar.gz, .gz, .png, .jpg, .mp4, .wasm 等)や正規パッケージマネージャー(npm, npx, cargo, rustc, dpkg, apt, tar 等)のキャッシュ作業を除外し、正規ツール展開時の誤検知による SIGSTOP 凍結を完全に防止します。
  • 同一ファイルの複数回上書き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 をマウント単位、/ をファイルシステム単位で監視。
  • notify-first・確認前隔離なし——YARA/ClamAV の単純なヒットで無確認の隔離や FAN_DENY は行いません。実シグネチャ検出は /run/roamswitch/approvals.json にモーダル要求(隔離/許可/後で)を積み、ユーザーが確認するまで Vault には入りません。実際の execve のみ pre_exec_blocking_enabled が有効なとき FAN_DENY します。承認タイムアウトはフェイルオープン。
  • EICAR 等のテスト署名は通知のみ——業界標準のテスト文字列は「無害」として情報通知を出すだけで、隔離も遮断もしません(fanotify ガード・ダウンロードガード双方で)。
  • ユーザー設定の scan_exclusions(配下も含む絶対パス。旧 clamav_exclusions を統合)を YARA・ClamAV 双方が尊重。承認ダイアログの「許可」と隔離タブの「復元」はどちらもこの一覧に追記され、同じファイルが再び拾われません。
  • 検出・確認された実マルウェアは ~/.local/share/roamswitch/quarantine/ へ退避。Vault ディレクトリは 0700、検体は 0400(読み取り専用・実行不可)。復元時はファイルを 0644 に戻し、元ディレクトリの所有者へ chown。
  • 許可イベントループはファイル I/O を一切行いません——設定の読み取りは専用のバックグラウンドスレッドが Mutex<GuardConfig> スナップショットへ行い、ホットパスはロック+コピーのみ。FAN_OPEN_PERM を遅延させてマシンを固まらせないための設計上の不変条件です。
  • ClamAV がある場合、新規ダウンロード実行ファイル(.sh.deb.elf 等)と危険な AI モデル(.pkl.pt)をローカル DB でスキャン。ClamAV は任意の依存で、未インストールでも他の防御は動作。インストールされている場合、日次アップデータ(§11)が freshclam を実行しシグネチャ DB を最新に保つ。

カーネル特権昇格(LPE)防護とカーネル堅牢化

非特権ユーザー空間を取得した攻撃者やマルウェアが、Linux カーネルの脆弱性を悪用して root 権限を奪取することを多層防御で阻止します。

  • 非特権 User Namespace の無効化(Frag Gap CVE-2026-53362 対策) — 現代の Linux カーネル特権昇格脆弱性の多くは、非特権ユーザーが unshare(CLONE_NEWUSER) を呼び出して作成したユーザー名前空間内で、未初期化構造体や古いネットワークサブシステムへ不正アクセスすることに起因します。RoamSwitch は user.max_user_namespaces = 0(または kernel.unprivileged_userns_clone = 0)を推奨・診断し、ワンクリック堅牢化で適用。これにより未パッチのゼロデイ脆弱性であっても非特権プロセスからの攻撃経路を根本から遮断します。
  • Yama LSM によるメモリ保護kernel.yama.ptrace_scope = 1(または 2)を適用し、一般プロセスが他のプロセスへ ptrace でアタッチしたり、/proc/$pid/mem 経由でメモリ空間(ブラウザのセッションや SSH/GPG 秘密鍵)を読み取ることを拒絶します。
  • コアダンプ抑止fs.suid_dumpable = 0 により、クラッシュしたプロセスのメモリイメージがディスク上に平文ダンプされることを防止します。
  • /tmp & /dev/shmnoexec マウント防御 — 一時ディレクトリにペイロードを配置して実行することを防ぐため、外出先(未信頼ネットワーク)では noexec,nosuid,nodev でマウントする防御機構を提供します。

eBPF ランタイム脅威監視 & 自動プロセス凍結 (Desktop eBPF Guard)

RoamSwitch クライアントデーモンは、カーネル空間で動作する Modern eBPF センサー(Falco / Tetragon / BTF)との連携機構を標準搭載します。

# eBPF ランタイム脅威検知と自律迎撃フロー
[悪性プロセス (LPE/マルウェア)]
    │ 不正システムコール実行 (Frag Gap 悪用試行)
    ▼
[Linux カーネル (eBPF プローブ)]
    │ eBPF リングバッファ (2MB コンパクト設計)
    ▼
[Falco (RoamSwitch Optimized)]
    │ メモリ上 UNIX ソケット直接通信 (/var/run/roamswitch/events.sock)
    ▼
[roamswitch-daemon (root)]
    ├─► ① 攻撃プロセスのミリ秒凍結: kill(pid, SIGSTOP) [状態: Ts]
    ├─► ② ネットワーク完全遮断: nftables input/output drop [Air-Gap 展開]
    └─► ③ デスクトップ緊急通知: GTK3 モーダル & libnotify アラート
  • UNIX ドメインソケット直接連携(/var/run/roamswitch/events.sock — Falco 等の eBPF センサーから、ディスクログを経由することなくメモリ上の UNIX ソケット経由でアラートを直接受信。ディスク I/O を発生させず、ミリ秒単位の超高速ハンドオフを実現します。
  • ミリ秒単位の自律対応(プロセス凍結 & Air-Gap 展開) — 受信したイベントの優先度が Critical または Emergency(カーネル LPE、特権昇格、ランサムウェア暗号化など)に達した場合、デーモンは即座に当該 PID に対し SIGSTOP を送出してプロセスを完全停止(状態: Ts)させ、inet roamswitch テーブルに policy drop(Air-Gap)を展開してデスクトップ通知を発報します。
  • デスクトップ向け低オーバーヘッド & ログ肥大化防止チューニング(RoamSwitch Optimized) — ラップトップやワークステーションのバッテリー消費・CPU 負荷・ディスク枯渇を抑止するため、最適化プロファイル(99-roamswitch-optimized.yaml)を同梱:
    • 重要度フィルタリング(priority: warning — 日常操作のノイズを 95% 削減。
    • カーネル事前破棄(drop_failed_exit: true — 失敗システムコールをカーネルドライバ段階で破棄し CPU 負荷を半減。
    • 省メモリリングバッファ(cpus_for_each_buffer: 2 — バッファサイズを 2MB に縮小し常駐メモリを 30〜50MB、CPU 負荷を 1% 未満に抑制。
    • ログ上限強制ローテーション(/etc/logrotate.d/roamswitch-falco — 50MB 上限・7 世代圧縮保持。
  • スタンドアロン堅牢化 vs eBPF 拡張のハイブリッド耐性 — Falco 未導入時でもカーネル sysctl(user.max_user_namespaces = 0)・nftables プロファイル・fanotify・カナリア監視で自律防衛。Falco 導入時はリアルタイム eBPF イベントによるゼロデイ迎撃・プロセス凍結が加わり、最高強度の防衛を実現します。

§6BadUSB 対策

USB イベントを監視し、キーボード(HID)クラスのデバイスと USB マスストレージを追跡します。既定 OFF(macOS 版の USBKeyboardGuard / USBStorageGuard と同じく isEnabled = false 出荷)。初回セットアップ ウィザードと USB タブからオプトインでき、有効化時には確認ダイアログを出します。

不正 USB キーボード(キーストローク注入)

  • カーネル層でのポート物理切断は行いません(重要)。旧実装(≤1.0.6)は未登録キーボードに対して /sys/bus/usb/devices/*/authorized0 を書き、デバイスを物理的に切断していました。キーボードとマウスが一体の受信機(Raspberry Pi・ミニ PC で一般的)ではマウスも同時に切断し、内蔵入力の無いマシンを操作不能にします。現在は HID インターフェース(bInterfaceClass 03)を持つデバイスへの authorized=0 書き込みをハード拒否し、デーモンは起動時に authorized==0 の HID デバイスを再認可して過去バージョンで切断されたマシンを自己修復します。
  • キーストロークの遮断はソフトウェアで行います。未登録キーボードを検知すると、そのデバイスの /dev/input/eventN/proc/bus/input/deviceskbd ハンドラを持つノードのみ、VID:PID 一致)に evdev の EVIOCGRAB で排他グラブをかけます。マウスノードは触りません。macOS 版の CGEventTap に相当し、デバイスは給電されたままです。
  • 安全策 — グラブをかけるのは「他に入力できるキーボードがある」場合(内蔵、または承認済みで接続中の USB キーボード)のみ。単一の新規キーボードしかないマシンを締め出しません。
  • 承認ダイアログ — グラブと同時に /run/roamswitch/approvals.json に承認要求を積み、GUI がモーダル(許可/拒否)を表示。許可でホワイトリスト登録+グラブ解除。3 分でフェイルオープン。

不正 USB マスストレージ

未登録の USB マスストレージ(HID を持たないもの)が挿入され、ガードが有効かつ未信頼ネットワーク/lockdown のとき、authorized=0 で保留し(HID を持たないので安全)、承認ダイアログを表示します。許可で再認可+ホワイトリスト登録、拒否で保留を継続。macOS 版は 1.7.4 でこの「読み取り専用で保留+承認プロンプト」方式に統一しました。

識別と grandfathering

HID の判定は bInterfaceClass == "03"/proc/bus/input/devicesHandlers= 行。コンボ受信機(1 つの VID:PID で kbd と mouse の両セクション)は VID:PID でマージ。デーモン起動時に接続済みの未登録キーボードは grandfathering され、以降にホットプラグされたものだけがグラブ対象になります。

§7セキュリティ健全性診断(24 項目)

roamswitch-coreLinuxHealthChecker が 24 項目を評価し、0〜100 のスコアと A〜F の等級、各項目の改善アドバイスを生成します。GTK ダッシュボード・CLI(roamswitch status)・MCP(get_security_report)のいずれからも、全 24 項目のタイトル・詳細・推奨文が利用者の言語で 表示されます(10 言語対応)。

診断カテゴリ
分類項目例
ディスク・ブートLUKS / dm-crypt 暗号化、UEFI Secure Boot
アクセス制御LSM(AppArmor / SELinux)、SSH / sudo 設定監査
カーネル堅牢化sysctl 強化、非特権 User Namespace 無効化(Frag Gap 対策)、コアダンプ制御、/tmp/dev/shm の noexec
更新自動セキュリティアップデートの設定
ネットワークARP スプーフィング監視、ゲートウェイ ARP/NDP 固定状態、外部公開ポート監査、Wi-Fi 暗号化強度
マルウェアClamAV / fanotify(ガードの実稼働も確認)/ エントロピー監視 / noexec
ブラウザFirefox / Chrome / Chromium の Safe Browsing 設定
DNS / USB脅威保護 DNS、USB バスのゼロトラスト状態

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

信頼ネットワークを踏まえた判定。 RoamSwitch が信頼(自宅)ネットワークで意図的に見送る堅牢化——ゲートウェイ MAC の PERMANENT 固定(ルーター再起動で LAN が不通になるのを防ぐ)、/tmp/dev/shm の noexec 化(ビルドや一部インストーラの互換性のため)、既定スコープの脅威保護 DNS——は 🔴「未対策」ではなく 🟢+説明で表示し、未信頼ネットワーク接続時に自動適用される旨を明記します。ランタイムの真値はデーモンが毎サイクル書き出す /run/roamswitch/state.jsonactive_levelnetwork_trustedfanotify_ready)から取得します。fanotify 項目はカーネル対応の有無だけでなく、ガードが実際にマーク済みで稼働しているか(/run/roamswitch/fanotify.ready)を確認します。外部公開ポート項目はデーモンの実プロファイルを参照します(MCP 版のハードコードを廃止)。

項目ごとの個別強化。 要対策項目のうち自動修復が可能なもの(カーネル sysctl/Yama/コアダンプ、/tmp noexec、USB ゼロトラスト、ゲートウェイ ARP 固定、脅威保護 DNS、fanotify 停止時のデーモン再起動)には、GTK ダッシュボードに「🔧 個別強化」ボタンを表示します。デーモンが root で実行するため、再起動以外に pkexec は不要です。

§8Model Context Protocol(MCP)サーバー

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

公開ツール
ツール内容
get_security_report24 項目診断・スコア・改善案
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外部通信の検証

RoamSwitch for Linux が行う外向き通信は 1 種類だけです——日次アップデータによる署名付きマニフェストの GET(§11)。それ以外の診断・検知・監査はすべてローカルで完結します。RoamSwitch for Linux はプロプライエタリ・フリーウェアでソースは公開していないため、下記の検査は lafine が実施したもので、結果を 9.2 に、付録 C の手順(配布パッケージだけで再現可能)を示します。

9.1 監査方法

  1. クレートの隔離 — HTTP/TLS スタックを許可するのは 1 クレートのみ、タイマー駆動のアップデータバイナリをビルドする roamswitch-updaterscripts/audit_no_network.sh(CI でゲートあり実行)は、roamswitch-coreroamswitch-daemonroamswitch-approamswitch-mcproamswitchkit のいずれかが reqwest / hyper / ureq / rustls / native-tls / openssl を引き込むか、roamswitch-updater 以外の .rsTcpStream / TcpListener / UdpSocket / to_socket_addrs / lookup_host を使う場合にビルドを失敗させる。
  2. 依存ツリーの検査Cargo.lock 全体をテレメトリ/解析/クラッシュレポート SDK(sentryopentelemetry 等)について検索。
  3. roamswitch-updater のレビュー — 単一のリクエスト先、クエリ文字列・Cookie・識別ヘッダの不在、ダウンロードするすべてに対する Ed25519 検証。
  4. サブプロセス呼び出しの列挙Command::new(...) の全呼び出し箇所を確認。

9.2 結果

監査結果
監査項目結果
HTTP / TLS スタックroamswitch-updater のみに存在(ureq + rustls)。core / daemon / app / mcp / kit には無し
テレメトリ/解析/クラッシュレポート SDKどこにも存在しない
TcpStream / TcpListener / UdpSocketroamswitch-updater 以外に 1 箇所も無し
使用されるソケット APIAF_UNIX(ローカル IPC)/AF_NETLINK(NFQUEUE verdict チャネル・nftables・ip neigh 制御——送出なし)/AF_INETroamswitch-updater のみ。VPN トンネル(§4)を有効にした場合は wg-quick(WireGuard バックエンド)または tailscaled(Tailscale バックエンド)——いずれもデーモンではなくサブプロセス——がユーザー自身のエンドポイント/tailnet へ送出
日次アップデータ約 24 時間ごとに GET https://lafine.net/updates/v1/manifest を 1 回。クエリ文字列なし・Cookie なし・汎用 User-Agent・識別子なし。全ペイロードを Ed25519 で検証。updates.enabled = false で完全停止
VPN トンネル(§4)既定 OFF。有効時、wg-quickユーザーの .conf に書かれた自分の VPN エンドポイントへトンネルを張る(lafine とは無関係)。ホスト名解決は getent ahosts(glibc NSS)で、Rust のソケット API は不使用
ライセンス認証Ed25519 署名のオフライン検証。認証サーバーへの通信なし
結論

RoamSwitch for Linux が開始する外向き通信は 1 種類だけ——利用者・端末に関する情報を一切含まない、日次・受信専用の署名付き検出データのダウンロードです。製品のそれ以外の部分が外部サーバーへ接触することはありません。

9.3 外部に触れる動作の全リスト

直接・間接を問わず、ローカルマシン外へパケットが出る可能性のある動作の全て:

#動作通信先発生条件送信内容
1日次アップデータGET /v1/manifest、およびフィードのバージョンが変わった時はフィードファイルlafine.net/updates/v1(CDN)systemd タイマー、約 24 時間ごと(ランダム遅延あり)。updates.enabled = false または roamswitch-update.timer 無効時は発生しない素の HTTPS GET:クエリ文字列なし・Cookie なし・汎用 User-Agent利用者や端末に関する情報は一切なし。署名付きマニフェスト+フィードを受信
1afreshclam(ClamAV 自身の更新ツール)。ClamAV 導入時に日次アップデータが起動ClamAV プロジェクトの CDN#1 の一部としてClamAV 本体(別プロジェクト)の通信。RoamSwitch は起動するだけ
2ping -c1 -W1 <ゲートウェイIP>LAN のデフォルトゲートウェイ(リンクローカル)ARP スプーフィング検知の際に ARP キャッシュを更新するためICMP エコー要求のみ。DNS 解決なし、ペイロードなし
3システムブラウザの起動(xdg-openhttps://lafine.net/...(製品サイト)「リリースノートを開く」等のボタンをユーザーが押した時のみRoamSwitch プロセスはソケットを開かない。URL を OS のブラウザに渡すだけ
4resolvectl dns <iface> …— (通信は発生しない)未信頼ネットワークでの脅威保護 DNS(オプトイン)。<iface> はデフォルトルートを持つ物理 NIC 全て(有線+無線の同時接続に対応。lotailscale*wg*docker*veth* 等は除外)。dns_scope = always_on なら信頼ネットワークでも適用。sentinel が毎サイクル reconcileOS のリゾルバ設定を変更するのみ。RoamSwitch 自身は DNS クエリを送らない
5パッケージマネージャによる更新ディストリの apt / dnf / zypper リポジトリユーザーが apt upgrade 等を実行、または GUI の「今すぐアップグレード」ボタン(pkexecapt-get / dnf / zypper)を押した時RoamSwitch はローカルの apt-cache policy 出力を読み、パッケージマネージャを起動するのみ。lafine とは無関係
6VPN トンネル(§4) — WireGuard バックエンド: wg-quick が張るトンネル/Tailscale バックエンド: tailscale set --exit-node で全通信を Exit Node 経由にユーザー自身の VPN エンドポイント/tailnet(WireGuard は .conf で指定、Tailscale は選んだ Exit Node と DERP リレー)vpn_on_untrusted_enabled かつ未信頼ネットワーク接続時。既定 OFF暗号化された WireGuard/Tailscale トラフィック。宛先はユーザー自身の VPN サーバー/tailnet であり lafine とは無関係。WireGuard のホスト名解決は getent ahosts(glibc NSS)、Tailscale は tailscaled(別プロセス)が制御

上記以外の RoamSwitch のすべての機能(nftables 制御、neigh テーブルの ARP/NDP 固定(ip neigh、パケット送出なし)、リンクガード(NFQUEUE、AF_NETLINK のみ)、ポートスキャン(ss の出力解析)、ARP 監視、健全性診断、エントロピー監視、カナリア、fanotify、USB 監視(evdev グラブ)、隔離、ログ監査、URL・秘密情報の監査)は ローカルのファイル読み取りとサブプロセス出力の解析のみ で完結します。§4 の VPN トンネルは唯一の「ユーザーが明示的に設定した外向き通信」ですが、その宛先はユーザー自身の VPN サーバーであり lafine のインフラには一切データが流れません。

§10プライバシーとデータの取り扱い

  • アカウント不要 — ユーザー登録・ログイン・メールアドレスの入力は一切ありません。
  • 設定はローカルのみ~/.config/roamswitch/config.json に平文で保存され、マシン外に出ません。クラウド同期は存在しません。
  • 診断結果はローカルのみ — セキュリティレポート・ログ監査結果は画面表示と(ユーザーが選べば)ローカルファイルへのエクスポートのみ。
  • ライセンスキーはオフライン検証 — Pro / Business のライセンストークンは Ed25519 署名を含み、公開鍵で検証されます。lafine のサーバーへ問い合わせません。
  • クラッシュレポートなし — パニック時もスタックトレースを外部送信しません。
  • 日次アップデータは利用者情報を一切送らない — クエリ文字列なし・Cookie なし・端末やインストールの識別子なし・汎用 User-Agent。これはレポートではなくダウンロードです。リンクガードの判定結果・遮断したホスト・スキャン結果はローカルのアクティビティビュー/journald にのみ記録され、送信されません。

§11ライセンスと配布

エディション
エディション対象価格ライセンス
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 フロア検証」ステップを設け、2.36 を超える依存が混入した場合はビルドを失敗させる。
  • 署名鍵の管理 — apt/rpm リポジトリ署名の秘密鍵は GitHub Actions の暗号化シークレットにのみ存在し、リポジトリには公開鍵のみをコミットする。

11.3 日次アップデータ

roamswitch-updatersystemd タイマー(roamswitch-update.timerOnCalendar=daily+ランダムな 3 時間の遅延、Persistent=true)で実行される単独バイナリです。ネットワークに接触する唯一のコンポーネントです。各実行で:

  1. GET https://lafine.net/updates/v1/manifest とそのデタッチ署名。
  2. マニフェストの Ed25519 署名を検証。脅威フィード専用の署名鍵を用いる(本体アップデート用の Sparkle 鍵とは別鍵)。フィードはサーバ側 CI が毎日再署名するため、その秘密鍵は CI シークレットに置かれる。鍵をフィードに限定するのが要点で、万一漏れても攻撃者が配れるのは不正なブロックリストのみ(sinkhole/警告のみ。コード実行経路も本体更新経路もない)。本体アップデートの署名鍵は macOS キーチェーンから出ない。検証できないマニフェストは破棄され、無署名データにフォールバックすることはない。
  3. 脅威フィードのバージョンが変わっていれば、フィードを取得し、SHA-256 と Ed25519 署名を検証してリンクガード(§4)向けにアトミックに設置する。
  4. ClamAV が導入されていれば freshclam を起動する。
  5. 本体の最新バージョンを通知用に記録する(アップデータは本体をインストールしない。Linux ではユーザーが apt upgrade を実行する)。

いずれかの手順の失敗(オフライン、署名不正、freshclam 不在)は updates.lastError に記録され、プロセスは常に exit 0 で終了するため、タイマー実行が systemd の失敗通知を出すことはありません。機構全体は updates.jsonupdates.enabled = false、または systemctl disable --now roamswitch-update.timer で無効化でき、その場合はパッケージ同梱のデータのみで動作します。脅威フィードはパッケージに同梱もされているため、新規インストール直後から機能し、アップデータを無効にしていても apt upgrade で更新されます。

§12動作環境

  • 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
  • 必須: systemdnftablesiproute2ip neigh — ARP/NDP 固定)(.deb / .rpm の依存で自動導入)
  • 任意: clamav(マルウェアスキャン)、nmcli(Wi-Fi 暗号化判定)、libnotify(デスクトップ通知)、wireguard-tools(VPN トンネル + キルスイッチの WireGuard バックエンド、§4)、tailscale(同 Tailscale バックエンド、§4)、polkit / pkexec(GUI からのアップグレード実行)
  • 非対応: 非 systemd 系ディストリ(Alpine / Void / Devuan)
  • 画面: 1280×720 以上(画面サイズに応じてウィンドウとフォントを自動スケール。Raspberry Pi の小型ディスプレイに対応)

付録 A直接依存クレート一覧

クレート用途ネットワーク
serde / serde_json設定・IPC のシリアライズなし
tokio非同期ランタイム(features = ["full"] だが使用は Unix ソケットのみ)なし(TCP 未使用)
tracing / tracing-subscriberログ出力(ローカル・journald)なし
thiserror / anyhowエラー処理なし
regex文字列解析(診断・CSS スケーリング)なし
urlURL のパース(audit_url_safety のヒューリスティック)なし(取得しない)
chrono日時処理なし
ed25519-dalekライセンス署名のオフライン検証なし
base64 / sha2ライセンストークン・カナリアのハッシュなし
libcchown / kill / システムコールなし
idnaホモグラフ検知のための IDN/punycode ホストのデコードなし
nfq(daemon のみ)リンクガードの NFQUEUE バインディング——純 Rust、AF_NETLINKなし(verdict チャネル、送出なし)
open「リリースノートを開く」で xdg-open を呼ぶプロセス自体は通信しない
GTK3 / ksni(app のみ)GUI とトレイなし
ureq + rustls(roamswitch-updater のみ日次アップデータの HTTPS GET 1 回依存ツリー中で唯一の HTTP/TLS スタック。アップデータバイナリに限定
要点

roamswitch-coreroamswitch-daemonroamswitch-approamswitch-mcproamswitchkit には HTTP クライアント・TLS スタック・テレメトリ SDK は現れません。ureq + rustlsroamswitch-updater にのみ存在します(CI の scripts/audit_no_network.sh が強制)。テレメトリ SDK はどこにも無し。

付録 Bnftables テーブル構造

table inet roamswitch {                 # プロファイル ファイアウォール(Air-Gap / balanced / lockdown)
    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 のみ許可
    }
}

table inet roamswitch_linkguard {        # §4.5 — プロファイルテーブルとは独立
    chain output {
        type filter hook output priority 0; policy accept;
        udp dport 53                       queue num 92 bypass
        tcp dport 53                       queue num 92 bypass
        tcp dport { 80, 443 } ct state new,established queue num 92 bypass
    }
}

table inet roamswitch_dev_guard {        # §4 ポート異常ガード/手動のポート隔離、別テーブル
    chain input {
        type filter hook input priority -10; policy accept;
        iif != "lo" tcp dport { … } drop
    }
}

table inet roamswitch_vpn {              # §4 WireGuard バックエンドのキルスイッチ
    chain output {
        type filter hook output priority -150; policy drop;
        oifname "lo" accept
        oifname "roamswitch" accept
        meta l4proto { icmp, ipv6-icmp } accept
        udp sport 68 udp dport 67 accept          # DHCP
        ip  daddr { <endpoint v4> } udp dport <port> accept
        ip6 daddr { <endpoint v6> } udp dport <port> accept
        ct state established,related accept
    }
    chain input  { type filter hook input priority -150; policy drop; … }  # 対称
}

table inet roamswitch_ts {               # §4 Tailscale バックエンドのキルスイッチ(よりゆるい)
    chain output {
        type filter hook output priority -150; policy drop;
        oifname "lo" accept
        oifname "tailscale0" accept
        meta l4proto { icmp, ipv6-icmp } accept
        udp sport 68 udp dport 67 accept          # DHCP(v6 も対称)
        ip  daddr 100.64.0.0/10 accept            # tailnet CGNAT
        ip6 daddr fd7a:115c:a1e0::/48 accept
        ip  daddr 100.100.100.100 udp dport 53 accept   # MagicDNS
        ip  daddr 100.100.100.100 tcp dport 53 accept
        udp dport 3478 accept                     # STUN
        udp dport 41641 accept                    # WireGuard 直結
        tcp dport 443 accept                      # DERP フォールバック
        ct state established,related accept
    }
    chain input  { type filter hook input priority -150; policy drop; … }  # 対称
}

ゲートウェイ/IPv6 ルーター/DNS の ARP・NDP 固定(§4)は nftables ではなく カーネルの neigh テーブルip neigh replace … nud permanent)で行われます。固定エントリの記録は /var/lib/roamswitch/arp_lock.json

付録 Cセルフチェック

本書の主張は、いずれも利用者自身の手元で確認できます。以下は roamswitch をインストールした環境で実行できます。

C.1 通信の検証

daemon / app / MCP バイナリに HTTP / TLS ライブラリがリンクされていないこと:

for b in roamswitch-daemon roamswitch-app roamswitch-mcp; do
  ldd "$(command -v $b)" | grep -iE 'ssl|crypto|nghttp|curl' && echo "  ^ in $b"
done
# → 出力なし。HTTP/TLS スタックは roamswitch-updater にのみ静的リンクされている。

稼働中のデーモンがインターネットソケットを開いていないこと:

sudo lsof -p "$(pgrep -x roamswitch-daemon)" -a -i
# → 出力なし = TCP/UDP のインターネット接続は 1 つも無い
sudo lsof -p "$(pgrep -x roamswitch-daemon)" -a -U | grep roamswitch
# → /run/roamswitch/roamswitch.sock のみ(リンクガードは AF_NETLINK ソケットを
#   追加するが、これはカーネルチャネルでありインターネットソケットではない)

RoamSwitch 由来の外向き通信は日次アップデータだけであること:

watch -n 5 'sudo ss -tupn | grep -E "roamswitch-(daemon|app|mcp)" || echo "(none)"'
# → 常に "(none)"。この 3 つはインターネットソケットを一切開かない。
systemctl list-timers roamswitch-update.timer
sudo systemctl start roamswitch-update.service
journalctl -u roamswitch-update.service -n 20 --no-pager
# → lafine.net/updates/v1 への HTTPS GET が 1 回だけ、その後終了。

無効化して完全な沈黙を確認する:

sudo systemctl disable --now roamswitch-update.timer
# または /var/lib/roamswitch/updates.json を "enabled": false に編集
sudo strace -f -e trace=network -p "$(pgrep -x roamswitch-daemon)" 2>&1 | grep -i 'connect('
# → AF_UNIX / AF_NETLINK への connect のみ。AF_INET / AF_INET6 は一切現れない。

C.2 防御機構の再現検証(Docker テストスイート)

RoamSwitch の各種防衛機構(Air-Gap 遮断、ファイアウォール強制消去時の自己修復、ランサムウェア検知、/tmp noexec、Yama LSM、ホモグラフ検知など全 17 項目)は、ホストマシンの通信環境や設定を一切損なうことなく、公式サポートリポジトリ(roamswitch-support)で公開されている Docker テストスイートを用いて手元で 100% 安全に再現実行できます。

# 検証スイートの取得と再現実行(公式配布パッケージを用いて隔離コンテナ内で自動検証)
git clone https://github.com/lafine1211/roamswitch-support.git
cd roamswitch-support/test/docker
docker build -t roamswitch-test .
docker run --rm --privileged roamswitch-test

テストコンテナは公式 APT リポジトリ(lafine.net/apt)から配布パッケージを自動取得し、独立した名前空間内で以下の体系的検証項目(SP-1〜11、PENT-1〜7)を自動実行・判定します。

(1) 自律ネットワーク防衛 & Air-Gap 自己修復

IDシナリオ検証手法判定基準
SP-3Air-Gap 有効化 → 外部遮断enable_air_gap IPC 送信output フックに policy drop が適用され、外部通信が完全遮断
SP-3b防火壁強制消去時の自己修復nft delete table inet roamswitch による強制ルール削除Anti-Clobber Self-Healing が 5 秒以内に遮断ルールを自動再展開
SP-3cデーモン再起動時のフェイルクローズドAir-Gap 中にデーモンを強制終了(SIGKILL)して再起動再起動後も Air-Gap 遮断状態が自動で引き継がれる
SP-3dAir-Gap 正規解除 → 通信復旧disable_air_gap IPC 送信drop ポリシー解除、全マーカーファイル削除、外部通信が即時復旧
SP-8予防的 ARP/NDP 固定独立 netns ゲートウェイ環境で有効化 → 偽の gratuitous ARP 送出ゲートウェイ neigh エントリが PERMANENT を維持し、偽 ARP を拒否
SP-9VPN キルスイッチ(WireGuard)実 WireGuard サーバー(別 netns)を立て .conf import → vpn_upinet roamswitch_vpnpolicy drop)下でハンドシェイク成立。トンネル死後も漏洩ゼロ
SP-10VPN キルスイッチ(Tailscale)スタブ tailscale CLI +独立 netns、tailscale0 IFトンネル外の平文 TCP/80 とローカル DNS を遮断し、DERP(TCP/443)と MagicDNS を許可

(2) カーネル & マウント堅牢化(Kernel Hardening)

IDシナリオ検証手法判定基準
SP-11aネットワーク sysctl 堅牢化apply_kernel_sysctl_hardening IPC 実行rp_filter=1, tcp_syncookies=1, accept_redirects=0 等の 7 項目が目標値に設定
SP-11bメモリ保護 & Yama LSMptrace_scope および suid_dumpable の設定検証kernel.yama.ptrace_scope=1(他プロセス盗聴阻止)、fs.suid_dumpable=0(コアダンプ抑止)
SP-11c/tmp & /dev/shm noexec 防御apply_mount_hardening IPC 実行/tmp/dev/shmnoexec,nosuid,nodev で再マウントされ、シェル/バイナリ実行が拒否
SP-11dユーザー領域の実行性維持正当なホームディレクトリ(~/)でのスクリプト実行影響を受けず正常に実行可能(開発・日常運用に副作用を与えない)

(3) 多層マルウェア・ランサムウェア防御 & カナリア

IDシナリオ検証手法判定基準
SP-1ランサムウェアおとり(カナリア)改ざん検知~/Documents/ のカナリアファイル(.xlsx)を truncate / rename数秒以内に改ざん・移動を検知し Air-Gap を即時発動
SP-2ランサムウェア一括暗号化のバースト検知単一プロセスが短時間に多数の高エントロピーファイルを生成当該プロセスを SIGSTOP で即時凍結し Air-Gap を発動
SP-2bshred 等の正当ツールの誤検知防止shred -n 3 -u を複数ファイルに対し実行ホワイトリスト照合により誤検知・凍結が発生しない
SP-2c重要システムプロセスの非凍結バースト検知時の凍結対象ロジック検証dockerd, systemd, containerd 等の重要インフラプロセスを絶対に凍結しない
SP-4EICAR テスト文字列の非隔離EICAR テスト文字列を Downloads に書き込み情報通知のみを発報し、ファイルを勝手に隔離・削除しない
SP-4b実シグネチャ検知時の確認制隔離実マルウェアシグネチャを書き込み即時無断隔離せず、承認ダイアログを発行。ユーザー承認(quarantine_path)で退避
SP-4c隔離 Vault の権限堅牢化隔離 Vault ディレクトリおよび検体のパーミッション確認Vault ディレクトリ 0700、隔離検体 0400(読み取り専用・実行不可)
SP-4d原本安全復元(特権 IPC)restore_quarantine_file IPC 送信元ディレクトリの所有者権限(0644)で安全に復元し、除外リストへ登録

(4) 受動リンクガード・フィッシング防御

IDシナリオ検証手法判定基準
SP-7mode = block 強制遮断フィード掲載ホストおよび blocklistExtra ホストへ接続試行TLS 層(SNI パース)で即時 DROP。未掲載の正常ホストは HTTP 200 到達
SP-7bmode = warn fail-closed 動作警告対象ホストへ接続試行し、ユーザー無応答でタイムアウト(8秒)タイムアウト時に fail-closed(drop)。ユーザー明示「許可」時のみ通過
SP-7cmode = off 完全解除リンクガードを無効化inet roamswitch_linkguard テーブルが撤去されオーバーヘッドなし

(5) BadUSB 対策・デバイス制御

IDシナリオ検証手法判定基準
SP-6起動時接続キーボードの grandfatheringデーモン起動時に接続済みのキーボードを確認既存デバイスを正常認識。起動後の新規ホットプラグのみグラブ対象

(6) Docker 隔離環境での網羅的ペンテスト(侵入テスト 17 項目)

ID攻撃手法シミュレーション内容防御・検知判定基準
PENT-1C2 ExfiltrationAir-Gap 下での C2 宛て外部 HTTP/TCP 通信試行パケットフィルタにより全パケット即時 DROP
PENT-1bFW 強制消去攻撃nft delete table inet roamswitch による防御破壊Anti-Clobber Self-Healing が数秒以内に自動再展開
PENT-1cAir-Gap 正規復帰認証済み disable_air_gap IPC 送信DROP ルール撤去・全マーカー消去・通信完全復旧
PENT-2/tmp バックドア実行/tmp に設置した悪意あるシェルの実行試行noexec マウント防御により Permission denied 拒否
PENT-2b/dev/shm ペイロード実行共有メモリ /dev/shm に配置したバイナリの実行試行noexec マウント防御により実行遮断
PENT-2cユーザー通常実行性正当なユーザー領域(/home/tester/)でのスクリプト実行開発・日常作業への影響ゼロ(正常実行)
PENT-3ptrace メモリ奪取PTRACE_ATTACH でプロセスから秘密鍵・トークン抽出試行Yama LSM ptrace_scope=1 によりアタッチ拒否
PENT-3bコアダンプメモリ抽出プロセスクラッシュ時のコアダンプ生成を試行fs.suid_dumpable=0 によりコアダンプ生成抑止
PENT-4カナリア改ざん攻撃~/Documents/ のカナリアファイル(.xlsx)をゼロクリアサイズ異常・ハッシュ改変を即時検知
PENT-4bカナリア一括抹消カナリアファイルの完全削除を試行ファイル消失をリアルタイム検知しインシデント発報
PENT-5IP スプーフィング送信元 IP アドレスを偽装したパケットを送信rp_filter=1(リバースパスフィルタ)が自動破棄
PENT-5bSYN Flood DoS未完了接続を大量送信して接続テーブル枯渇を試行tcp_syncookies=1(SYN Cookies)でテーブル枯渇防護
PENT-5cICMP リダイレクト奪取不正な ICMP Redirect でルーティングハイジャック試行accept_redirects=0 によりリダイレクトを無視
PENT-6キリル文字ホモグラフ詐欺gооgle.com 等の同形異字を用いたフィッシング誘導LinkGuard が偽装特定、40点(DANGEROUS / block)判定
PENT-6b生 IP 直打ち・平文通信未暗号化の生 IP 直打ち接続試行リスクファクターとして正確に検知・警告
PENT-7OpenAI API キー漏洩コードやログに sk-proj-... トークンが含まれる事象エントロピー解析で検知し安全にマスク(sk-pro...YZ12
PENT-7bGitHub トークン漏洩コードやログに ghp_... トークンが含まれる事象シグネチャ・エントロピー解析で正確に特定
PENT-8カーネル LPE (Frag Gap) 悪用阻止非特権ユーザーによる unshare -U -r(CVE-2026-53362 悪用試行)user.max_user_namespaces = 0 により Operation not permitted で即時拒絶
PENT-9eBPF 脅威検知 → プロセス凍結 & 遮断Falco eBPF ソケット経由での Critical/Emergency アラート注入当該 PID を SIGSTOP でミリ秒凍結(状態: Ts)し Air-Gap を即時展開

(7) 侵入テスト実証総括(Falco なし [スタンドアロン] & Falco あり [eBPF 連携])

独立した Docker 侵入テスト環境(Target: Ubuntu 24.04 + RoamSwitch Client Edition、Attacker: Nmap / curl / hping3 等)にて実施した包括的ペンテスト(詳細は公式報告書 docs/CLIENT_PENTEST_REPORT.ja.md 参照)の結果総括:

検証項目Falco なし (スタンドアロン堅牢化)Falco あり (eBPF ランタイム防護)防御判定
外部ポートスキャン耐性 (Nmap SYN)合格Lockdown で 100% Filtered / DROP)合格Lockdown で 100% Filtered / DROP)外部完全ステルス化
外部直接アクセス遮断 (TCP/80, 3306)合格(タイムアウト遮断・無応答)合格(タイムアウト遮断・無応答)外部露出ゼロ
カーネル LPE (Frag Gap) 悪用防止合格(sysctl 堅牢化で unshare 根本遮断)合格(eBPF 即時検知 + SIGSTOP 凍結 + Air-Gap)多層防御確立
未許可ポート検知 (アノマリー)合格(0.0.0.0 公開プロセスを高リスク検出)合格(0.0.0.0 公開プロセスを高リスク検出)100% 検知・警告
ログ肥大化・CPU負荷対策ログ発生なし(ゼロオーバーヘッド)合格(ノイズ95%カット / バッファ2MB / 50MB上限)デスクトップ常駐最適化

C.3 既知の制約

制約影響対応
一部カーネルで 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 等の全体操作は避ける
リンクガードはブラウザの DoH を TLS SNI 経由でしか把握できず、ECH(Encrypted Client Hello)はそれも隠すECH が普及すると、ECH 対応サイトへの ECH 接続はホスト名で識別できないローカルのブロックリストとヒューリスティックは DNS/HTTP と非 ECH の TLS には引き続き作用する。リゾルバ経路は脅威保護 DNS(§4.5・オプトイン)でカバー
updates.enabled = false の場合、フィードの鮮度はリリース間隔に依存する更新を切ると、フィードは直近の apt upgrade 時点のものになる最重篤の検出(ブランドのホモグラフ)はフィード不要。常時最新が必要なら更新を再度有効化するか脅威保護 DNS を使う
この文書は RoamSwitch for Linux v1.6.0(カーネル LPE 堅牢化/eBPF ランタイム防護/攻撃プロセス SIGSTOP 凍結/Falco 低負荷最適化/リアルタイム監視 Vault 隔離および特権 IPC 原本復元/Air-Gap 自己修復機構)時点の実装に基づきます。項目単位の変更履歴は roamswitch-support の CHANGELOG を参照してください。最新情報は lafine.net/linux を参照してください。