§1
Linux용 RoamSwitch는 macOS RoamSwitch의 제로 트러스트 네트워크 방어 모델을 Linux(systemd + nftables 환경)에 제공하는 상주 네트워크 보안 및 시스템 진단 애플리케이션입니다.
이 버전은 클라이언트 시스템(워크스테이션, 랩톱, 단일 보드 컴퓨터)을 대상으로 하며 시스템이 네트워크 간에 이동할 때 시스템을 따르는 자율적인 동작을 가정합니다. 강화된 서버/헤드리스 인프라 버전(RoamSwitch Server Edition — 상시 기본 거부, 중요 경로 FIM 무결성, 원격 웹후크 및 정적 정책 적용)이 전용 서버 빌드로 제공됩니다.
게이트웨이 MAC 주소로 연결된 Wi-Fi/유선 네트워크를 식별하고 활성 nftables 방화벽 프로필을 자동으로 전환합니다. 또한 신뢰할 수 없는 네트워크에 3가지 중간자 방어 계층인 VPN 터널 + 킬 스위치(기본 방어인 WireGuard 또는 Tailscale), 예방 ARP/NDP 잠금 및 ARP 스푸핑 탐지 및 동작 랜섬웨어 탐지(fanotify + Shannon 엔트로피 + 카나리아), 수동 링크 가드를 제공합니다. 피싱 연결 플래그 또는 차단(NFQUEUE + SNI), 포트 이상 보호, BadUSB 완화, 커널 로컬 권한 에스컬레이션(LPE) 선점(Frag Gap CVE-2026-53362 완화), eBPF 런타임 위협 센서(Falco/Tetragon) 1초 미만의 프로세스 동결(SIGSTOP) 및 Air-Gap 네트워크와 통합 isolation, 24개 항목 보안 상태 평가 및 내장 MCP(Model Context Protocol) 서버.
이 백서는 각 방어 메커니즘의 아키텍처, 위협 모델 및 설계에 대해 설명합니다. 특히 "완전 로컬 처리, 시스템에서 전송되는 유일한 것은 서명된 탐지 데이터에 대한 요청이며 사용자에 대해 아무것도 전달하지 않습니다"의 원칙이 코드 수준에서 어떻게 보장되는지 설명합니다. 마케팅 언어를 피합니다. 배포된 패키지(바이너리)의 실제 동작과 비교하여 주장을 확인할 수 있으며 부록의 자체 점검도 가능합니다. Linux용 RoamSwitch는 독점 프리웨어이며 해당 소스 코드는 공개되지 않습니다(§11).
| 원리 | 세부정보 |
|---|---|
| 원격측정 제로 | 제품은 귀하나 귀하의 기계에 관한 어떤 정보도 누구에게도 보내지 않습니다. 원격 측정, 분석, 충돌 보고, 사용량 측정항목, 원격 구성 또는 라이선스 활성화 서버가 없습니다. |
| 수신 전용 업데이트 | 제품이 보내는 한 번의 아웃바운드 요청은 하루에 한 번 lafine.net/updates/v1에서 고정되고 서명된 매니페스트(링크 가드에 대한 사기 사이트 목록, ClamAV 서명 버전, 최신 앱 버전, 패키지 CVE 맵(Homebrew/npm/PyPI/crates.io/RubyGems/Packagist/Go/Maven), 실증형 취약점 진단의 CVE 맵, 그리고 오타스쿼팅 탐지에 사용하는 인기 npm 패키지 이름 목록)의 GET입니다. 여기에는 쿼리 문자열, 쿠키, 식별 헤더 및 귀하에 대한 정보가 포함되지 않습니다. updates.enabled = false는 완전히 끕니다. 그런 다음 제품은 외부 접촉 없이 번들 데이터로 실행됩니다. |
| 완전한 로컬 처리 | 모든 평가, 탐지 및 감사는 로컬 시스템에서 완료될 때까지 실행됩니다. URL 안전 분석 및 비밀 스캐닝은 입력 내용을 어디에도 전송하지 않고 경험적으로 평가합니다. |
| 최소 권한 | 권한 있는 작업은 루트 데몬으로 제한됩니다. UI, CLI 및 MCP 서버는 Unix 도메인 소켓 IPC를 통해 이를 요청합니다. 데몬은 TCP/UDP 소켓을 열지 않습니다. 링크 가드는 AF_NETLINK NFQUEUE 판정 채널(커널 ← 사용자 공간, 패킷 송신 없음)만 사용합니다. |
| 실패로 종료 | Air-Gap(긴급 격리)은 데몬을 다시 시작해도 유지되며 해당 규칙이 외부에서 삭제되면 몇 초 내에 다시 확인됩니다. |
| 오프라인 라이선스 | Pro/Business 라이선스는 Ed25519 서명 확인만으로 확인됩니다. 활성화 서버에 대한 호출이 발생하지 않습니다. |
§2
Linux용 RoamSwitch는 주로 신뢰할 수 없는 네트워크 간에 로밍하는 노트북/모바일 워크스테이션을 대상으로 합니다.
범위 내의 공격자
- 동일한 LAN의 공격자 — 공유 Wi-Fi의 포트 스캔, 중간자에 대한 ARP/NDP 스푸핑(악성 라우터 광고 포함), 악성 DHCP, MAC 플러딩 후 수동 스니핑, 개발 서버에 대한 무단 액세스 또는 실수로
0.0.0.0에 바인딩된 로컬 LLM API. - 악성 USB 장치(BadUSB) — 키보드를 가장하고 화면이 잠기기 전에 키 입력을 삽입합니다. 데이터 유출이나 악성 코드 운반을 위한 등록되지 않은 USB 대용량 저장 장치입니다.
- 랜섬웨어/파일리스 악성 코드 — 다운로드한 파일을 통해 침입하여 사용자 문서를 대량 암호화합니다.
- DNS 기반 C2 및 피싱 — C2 서버 또는 피싱 사이트에 도달하기 위해 이름 확인을 사용하는 악성 코드입니다.
범위 외
- 이미 루트를 보유하고 있는 공격자 커널 또는 펌웨어 수준 루트킷.
- 디스크를 물리적으로 제거하는 공격(전체 디스크 암호화 도메인, RoamSwitch는 암호화가 있는지 여부를 진단하지만 암호화하지는 않음)
- AirDrop 스타일 근접 무선 공유 제어(Linux에는 OS 기본 메커니즘이 없으며 지원되지 않음)
§3
Linux용 RoamSwitch는 7개의 상자에 걸쳐 Rust로 구현됩니다. 데몬과의 모든 통신은 /run/roamswitch/roamswitch.sock(Unix 도메인 소켓)을 통해 이루어집니다. 데몬, 앱 또는 MCP 서버에 수신 대기 중인 TCP/UDP 소켓이 없습니다. 앱 binds의 유일한 것은 두 번째 인스턴스를 방지하기 위한 단일 Unix 소켓입니다.
# 사용자 공간(비특권) 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-데몬 | 루트(시스템, Type=notify + WatchdogSec=30) | 모든 권한 있는 작업. 단일 작성자로서 nftables, DNS 및 systemd 장치를 제어합니다. |
| roamswitch 앱 | 로그인 사용자 | GTK3 GUI + AppIndicator 트레이. 구성 편집 및 시각화만 가능합니다. 모든 권한 있는 작업은 IPC를 거칩니다. |
| 로밍스위치(CLI) | 로그인 사용자 | 동일한 IPC 소켓을 사용하는 얇은 쉘 프런트 엔드. |
| 로암스위치-mcp | AI 클라이언트에 의해 생성된 프로세스 | stdio JSON-RPC. 읽기 전용 진단 정보를 제공합니다. |
데몬과의 모든 통신은 /run/roamswitch/roamswitch.sock(0700과 동등한 권한이 있는 디렉터리)을 통해 이루어집니다. 사용자 구성은 ~/.config/roamswitch/config.json에 일반 텍스트 JSON으로 저장됩니다. 데몬은 루트 권한으로 /home/*/.config/roamswitch/config.json을 읽습니다(HOME=/root로 실행됩니다). 구성은 기계를 떠나지 않습니다. 계정 등록도 없고 클라우드 동기화도 없습니다.
§4
센티넬 루프(기본적으로 5초 주기)는 /proc/net/arp 및 ip neigh에서 기본 게이트웨이의 MAC를 읽고 이를 config.json에 등록된 MAC와 일치시킵니다. SSID는 쉽게 스푸핑될 수 있으므로 SSID 대신 MAC을 사용합니다. 프로필 스위치가 스위치에 대한 이유(“등록되지 않은 네트워크” / “등록된 네트워크에 대한 설정 X” / “네트워크 연결 없음”)를 명시할 때 표시되는 바탕 화면 알림입니다.
| 프로필 | 상황 | nftables 동작 |
|---|---|---|
| 열기(신뢰할 수 있음) | 등록된 집 또는 회사 네트워크 | policy accept. 로컬 트래픽이 허용됩니다. |
| 균형 | 등록되지 않았지만 비교적 안전한 것으로 구성됨 | 기본 거부 인바운드. 설정된 연결과 lo만 허용됩니다. 노출 포트 노출이 모니터링됩니다. |
| 봉쇄(외출 보호) | 공용 Wi-Fi / 미등록 네트워크 | 모든 인바운드 패킷이 스텔스 삭제되었습니다. 공유 서비스가 자동으로 중지되었습니다(선택). |
모든 규칙은 inet roamswitch이라는 전용 nftables 테이블에 격리되어 있으며 다른 방화벽 구성(ufw/firewalld)과 절대 충돌하지 않습니다. 수동 재정의 만료(1시간/2시간/4시간/자정까지/지워질 때까지/다음 연결 끊김까지)는 데몬에 의해 단일 작성자로 적용됩니다. GUI는 만료를 기록하지 않습니다. 다음 틱에서 데몬이 다시 작성한 config.json을 다시 읽고 이를 UI에 반영합니다(충돌 방지).
Air-Gap(긴급 네트워크 격리)
inet roamswitch 테이블의 입력 및 출력 후크 모두에 policy drop(우선순위 -100)을 설정하고 lo만 허용하는 전체 격리 모드입니다.
- 실패 폐쇄 — 데몬을 다시 시작할 때 마커 파일(
/run/roamswitch/airgap.active)을 감지하면 격리가 다시 확인됩니다. - 자가 치유 — 외부 프로세스가
nft delete table을 사용하여 규칙을 삭제하면 센티넬 루프가 몇 초 내에 다시 적용됩니다. - 자동 만료 — 활성화 후 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 붙여넣기 검사기를 대체합니다.
- Interception — 전용 nftables 테이블
inet roamswitch_linkguard은output경로를 연결하고 NFQUEUE을 통해 사용자 공간 작업자에 대한 DNS 질문과 신규/초기 웹 연결을 대기열에 넣습니다. NFQUEUE는AF_NETLINK에 대한 커널‐사용자 공간 판정 채널입니다. 데몬은 소켓을 바인딩하지 않고 패킷을 생성하지 않습니다. 대기열 규칙은bypass을 전달하므로 작업자가 실행 중이 아닌 경우 트래픽이 방해 없이 전달됩니다(Air-Gap은 별도의 하드 중지로 유지됩니다). - Hostname 소스 — DNS 질문 이름, TLS ClientHello SNI(DoH를 사용하는 브라우저는 여전히 호스트 이름으로 보호됨) 및 일반 텍스트 HTTP
Host헤더. 암호화된 ClientHello(ECH)는 일단 널리 배포되면 알려진 사각지대입니다. - Verdict(
roamswitch-core, 순수 논리) — 호스트는 로컬 피싱/위협 피드 및 일련의 오프라인 경험적 방법(보호되는 브랜드의 IDN/혼동 가능한 동형어체, 비공식 도메인의 브랜드 토큰, 원시 IP 호스트, 고위험 TLD)에 대해 검사됩니다.
모드(linkGuard.mode) | 피드 히트 또는 브랜드 동형이의어 | 기타 의심스러운 신호 |
|---|---|---|
off | 검사받지 않음 | 검사받지 않음 |
warn | 연결은 최대 8개까지 유지 + 허용/차단 승인 프롬프트 | 알림만 |
block(기본값) | 연결이 끊어졌습니다 + 허용 대화 상자(호스트당 한 번) | 알림만 |
피드 히트 또는 브랜드 동형 호스트만 하드 차단됩니다. 휴리스틱 단독 플래그는 모두 경고입니다. warn 모드 사용자에게 요청하는 동안 위험한 호스트에 대한 연결을 최대 8초 동안 유지합니다. 응답 없이 보류가 만료되면 fail-closed입니다(패킷이 삭제되고 결과가 캐시되지 않음). "이 사이트가 괜찮습니까?"에 응답하지 않습니다. "예"를 의미해서는 안 되며 다음 시도에서 메시지가 다시 표시됩니다. block 모드는 호스트당 하나의 알림과 하나의 허용 대화 상자를 표시합니다(동일한 차단된 호스트에 대해 많은 연결을 여는 브라우저는 더 이상 알림을 넘치지 않습니다). 위험한 승인 대화 상자에서 기본 버튼은 "계속 차단"이고 "허용"은 조용하고 기본값이 아닌 선택으로 스타일 지정됩니다. 차단된 호스트는 영구적으로 허용되거나 알림(linkGuard.allowlist) 후 5분 동안 허용될 수 있습니다.
DNS는 검사되며 위조되지 않습니다: 차단된 DNS 질문은 알림만 생성합니다. 적용은 후속 TCP 연결에서 발생하므로 RoamSwitch는 합성 DNS 응답을 삽입하지 않습니다. feed은 피싱/사기 도메인의 컴파일된 목록으로, 패키지로 제공되고 일일 업데이트 프로그램(§11)에 의해 새로 고쳐집니다. 피드가 없으면 오프라인 휴리스틱이 계속 실행됩니다. 로드하기 전에 피드 파일의 Ed25519 서명을 확인합니다. 불량하거나 누락된 피드는 "경험적 접근만"에 실패하며 "모두 허용"에는 실패합니다.
VPN 터널 + 킬 스위치(기본 MITM 방어)
레이어 2의 무결성에 의존하지 않는 Anti-MITM 보호. 신뢰할 수 없는 네트워크에서 신뢰할 수 있는 엔드포인트에 대한 상시 암호화 터널은 로컬 ARP/NDP 스푸핑, 불량 DHCP 및 수동 스니핑을 부적절하게 만듭니다. 즉, 공격자는 암호 텍스트만 볼 수 있습니다. ARP/NDP 잠금 및 아래 감지는 이 기능의 부차적인 기능입니다.
선택할 수 있는 두 개의 백엔드 — "WireGuard(구성 파일)" 또는 "Tailscale(종료 노드)". RoamSwitch는 자체 암호화를 구현하지 않으며 VPN 제공자가 아닙니다. 두 백엔드 모두 선택적 종속성입니다. 없는 경우 GUI에 설치 명령이 표시됩니다.
(A) WireGuard 백엔드
- VPN 서버가 제공되지 않습니다 — 사용자가 제공하는 WireGuard 구성을 사용합니다: Mullvad, IVPN 또는 Proton VPN과 같은 공급자의
.conf또는 사용자 자체 WireGuard 서버(VPS 또는 홈 서버). 기본 구성은 제공되지 않습니다. - Config — 데몬은
.conf의 유효성을 검사하고 이를/etc/wireguard/roamswitch.conf(0600, 인터페이스roamswitch)에 저장합니다. 다른 곳에서는 살 수 없습니다. Ubuntu 24.04+ / Debian 13의 AppArmorwg-quick프로필은wg-quick이/etc/wireguard/외부에서.conf을 읽는 것을 거부합니다. 심지어 루트로도 마찬가지입니다. 분할 터널 구성(0.0.0.0/0/::/0이 아닌AllowedIPs)은 "모든 트래픽이 보호되지는 않음"으로 플래그가 지정됩니다. - Kill-switch — 전용 nftables 테이블
inet roamswitch_vpn(policy drop, 두 후크 모두) 은 루프백, 터널 인터페이스(roamswitch,oifname과 일치), 고정된 엔드포인트 IP에 대한 UDP, DHCP 및 ICMP을 제외한 모든 것을 삭제합니다. 터널이 시작되기 전에 전에 설치되므로(끝점은 먼저getent ahosts을 통해 고정 IP로 확인됨) 누출 창이 없습니다.wg-quick up이 실패하면 킬 스위치가 계속 작동됩니다.
(B) Tailscale 백엔드
- 이미 Tailscale을 실행하고 있는 사용자를 위한 것입니다. RoamSwitch는 가 아니라 실행
tailscale up/ 로그인 / 설치tailscaled을 수행합니다. —tailscale status --json를 읽고tailscale set --exit-node=<node>/--exit-node=(지우기)을 실행합니다. - 출구 노드가 필요합니다 — MITM 방지 보호는 모든 트래픽을 라우팅하는 출구 노드에만 적용됩니다. 아무것도 구성되지 않으면 보호가 활성화되지 않으며 UI에 "보호되지 않음"이라는 경고가 표시됩니다. 선택한 노드가 오프라인이 되면 보호 기능이 자동으로 해제되고 사용자에게 알립니다. 데드 노드를 통해 모든 것을 라우팅하면 연결이 블랙홀됩니다.
- Kill-switch (
inet roamswitch_ts,policy drop) — Tailscale의 전송은 단일 엔드포인트 IP(DERP 릴레이 + 로밍 피어)에 고정될 수 없으므로 이는 WireGuard보다 loser입니다. 이는 루프백, 터널 인터페이스(tailscale0), CGNAT 범위100.64.0.0/10및fd7a: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/3478,tcp/443, 전체 CGNAT/10)보다 허용 목록이 더 넓습니다. (2) 경로상의 공격자는 여전히 메타데이터(Tailscale이 사용 중, DERP 지역, 타이밍)를 보고 삭제/지연할 수 있지만 터널링된 페이로드를 읽을 수는 없습니다. (3) 직접 UDP가 차단되면 기밀성은 Tailscale의 자체 고정 인증서 DERP TLS에 있습니다. (4) MagicDNS가 꺼진 상태 + 로컬 확인자가 활성화된 동안 DNS가 중단됩니다(UI 경고). (5) 종속 포털은 활성화하기 전에 로그인해야 합니다.
Common — vpn_on_untrusted_enabled 및 네트워크를 신뢰할 수 없는 경우(level != open)에만 활성화됩니다. 신뢰할 수 있는 네트워크에서는 종료 노드가 지워지고 킬 스위치가 제거됩니다(tailscale down는 아님). 기본적으로 꺼져 있으며 선택되어 있습니다. WireGuard 터널/Tailscale 전송은 사용자의 VPN 엔드포인트/tailnet으로 이동하며 lafine의 인프라와 관련이 없습니다(§9).
예방적 ARP/NDP 잠금
신뢰할 수 없는 네트워크가 연결되는 순간, MITM 공격자가 가장해야 하는 온링크 인프라의 MAC 주소는 커널 인접 테이블에 PERMANENT(정적) 항목으로 고정됩니다. 일단 고정되면 커널은 스푸핑된 ARP 응답/이웃 광고를 무시합니다.
- 고정된 항목 — (1) IPv4 기본 게이트웨이, (2) IPv6 기본 라우터(종종 링크-로컬
fe80::주소), (3) 모든 온링크 DNS 확인자(공용 확인자는 게이트웨이를 통해 도달하고 건너뜁니다). IPv6 이웃은ip -6 neigh replace ... nud permanent로 고정되어 있습니다. - 신뢰할 수 있는 네트워크는 고정되지 않습니다 — 따라서 홈 라우터 재부팅으로 인해 사용자가 블랙홀에 빠질 수 없습니다. 모든 네트워크 스위치(TOFU)에 다시 고정됩니다. 다음 번 재연결 시 합법적인 장애 조치가 선택됩니다. 고정된 항목은
/var/lib/roamswitch/arp_lock.json에 기록됩니다. - 기본적으로 켜짐(Community Edition 정책, macOS Pro 빌드와 동일한 분류). 토글:
gateway_arp_lock_enabled.
ARP 스푸핑 탐지(알림 우선)
여러 MAC에 대한 하나의 IP 매핑과 게이트웨이 MAC의 의심스러운 갑작스러운 변경에 대해 /proc/net/arp을 모니터링합니다. 폐쇄 중: 모든 트래픽을 차단(Air-Gap) + 알림. 균형 잡힌/신뢰할 수 있는 네트워크에서: 절단하지 않고 알림; 사용자가 RoamSwitch에서 비상 Air-Gap을 트리거합니다. 이는 (a) 공격자가 단일 스푸핑된 ARP 패킷을 무기화하여 자체 중단을 초래하는 것을 방지하고 (b) 라우터 재부팅 또는 액세스 포인트 로밍이 실수로 이를 트리거하는 것을 방지합니다. 토글: arp_spoof_guard_enabled.
포트 이상 감시
외부 LAN(백도어, C2 또는 개발 서버/로컬 LLM API가 실수로 0.0.0.0에 바인딩됨)에 새로 노출된 수신 포트를 자동으로 포함합니다. 판정은 "위험한 포트 번호"가 아닌 baseline-relative입니다. 활성화되면 현재 노출된 실행 파일이 "알려진" 것으로 학습됩니다. 그 후에는 새로 등장한 노출 실행 파일만 플래그가 지정됩니다(ID = 실행 파일 경로, 스냅은 snap:<name>으로 정규화됨). 시스템 데몬은 범위를 벗어납니다. 포함은 inet roamswitch_dev_guard 테이블을 통해 이루어집니다. lo 이외의 다른 포트에서 해당 포트로 TCP를 삭제합니다. 머신 자체는 이를 계속 사용합니다. 자동 격리 시 즉각적인 데스크탑 알림 및 확인 대화 상자("이 포트 허용"/"차단 유지")가 표시되어 원클릭 영구 화이트리스트 지정이 가능합니다. 포트 진단 화면에서 모든 포트를 개별적으로 허용하고 기준선을 다시 캡처할 수도 있습니다. 기본적으로 켜져 있습니다. 토글: port_anomaly_guard_enabled. macOS에서 포팅되었습니다.
Docker 위험 감지 & 방화벽 우회 방지
Docker의 공개 포트(-p)는 호스트의 표준 방화벽을 우회하는 것으로 알려진 문제가 있어, DOCKER-USER 체인에 검사 규칙을 항상 삽입하여 허용되지 않은 외부 트래픽을 차단합니다(설정 불필요, 기본 항상 활성화). 또한 docker events를 실시간으로 감시하여 --privileged 컨테이너 시작이나 /var/run/docker.sock 마운트(컨테이너 탈출 위험)를 감지한 즉시 알려드립니다. 위험한 설정일 뿐 확인된 침해가 아니므로 자동 차단 없이 알림만 제공합니다.
기밀 정보・API 키 유출 스캐너
OpenAI・Anthropic・AWS・GitHub・Slack・Stripe 등의 API 키와 SSH 개인 키를 섀넌 엔트로피와 패턴 매칭으로 감지합니다. roamswitch audit-secrets <text|파일|디렉터리>로 텍스트・파일뿐 아니라 디렉터리 전체를 재귀적으로 스캔할 수 있습니다(.git・node_modules 등은 자동 제외, 2MB 초과・바이너리 파일은 건너뜀). audit_secrets MCP 도구와 Python SDK의 audit_secrets_directory()에서도 동일한 기능을 사용할 수 있습니다. 내용은 어디에도 전송되지 않습니다.
최초 실행 설정 마법사 및 확인 UI
패키지는 /etc/xdg/autostart/roamswitch.desktop을 제공하므로 설치 후 첫 번째 로그인 시 설정 마법사가 시작됩니다(이후에는 트레이 상주에만 해당). 보안 가드를 활성화/비활성화하면 macOS 빌드(포트 이상, ARP 자동 격리, USB 저장소, BadUSB 키보드, Bluetooth)와 동일한 가드에 대한 확인 대화 상자가 표시됩니다. 이벤트 시간 결정(알 수 없는 USB 키보드, 등록되지 않은 USB 드라이브, 알 수 없는 포트 자동 차단, 긴급 Air-Gap)이 모달 대화 상자로 표시됩니다.
§5
섀넌 엔트로피 버스트 감지 · YARA 스캐닝
쓰기 이벤트는 PID별로 추적됩니다. 단일 프로세스가 5초 내에 엔트로피가 7.92 이상인 distinct 파일을 20개 이상 생성하면 랜섬웨어 대량 암호화로 처리됩니다. 프로세스가 SIGSTOP으로 동결되고 Air-Gap이 트리거됩니다.
- YARA 검사와 엔트로피 추적의 완전한 분리 — YARA 악성 코드 검사는 기록된 모든 파일에 예외 없이 적용됩니다(제로 우회,
~/.cache/,node_modules/,/tmp/검사 및 아카이브 검사). 한편, 랜섬웨어 엔트로피 버스트 분석에서는 자연적으로 압축된 형식(.zip,.tgz,.tar.gz,.gz,.png,.jpg,.mp4,.wasm)과 검증된 패키지 관리자(npm,npx,cargo,rustc,dpkg,apt,tar)를 제외합니다. 거짓 긍정 SIGSTOP 정지를 제거하기 위해 빌드/캐시 트리에서 작동합니다. - 동일한 파일의 반복 덮어쓰기(예:
shred의 3회 패스)는 하나의 이벤트로 계산됩니다. - 중요 프로세스 보호 — PID는 하드 코딩된 NEVER_FREEZE 목록(
systemd,dockerd,NetworkManager,sshd,gnome-shell, …)에 대해 확인되며 절대 고정되지 않아 시스템 전체의 정지를 방지합니다.
카나리아(미끼 파일)
미끼 파일은 사용자의 문서, 데스크톱, 다운로드, 사진 폴더 및 전용 디렉터리에 배치되며 3초 주기로 SHA-256 기준과 비교됩니다. 이름 바꾸기, 삭제, 잘림 또는 콘텐츠 변경은 즉시 Air-Gap을 트리거합니다. 데몬은 루트로 실행되기 때문에 /home/*을 열거하고 모든 실제 사용자 디렉터리에 카나리아를 배포합니다.
fanotify 모니터링 · 격리 보관소 · ClamAV
- 데몬은
FAN_CLASS_CONTENT(대체FAN_CLASS_NOTIF)를 통해 마운트 수준에서/home,/var/tmp,/dev/shm를 모니터링하고 파일 시스템 수준에서/을 모니터링합니다. - 알림-우선, 자동 격리 없음. 순수 YARA/ClamAV 히트는 자동으로 격리되거나
FAN_DENY'd되지 않습니다. 실제 서명은/run/roamswitch/approvals.json(격리/허용/나중에)에서 모달 요청을 발생시킵니다. 사용자가 확인할 때까지 저장소에는 아무것도 입력되지 않습니다. 실제execve만FAN_DENY'되고,pre_exec_blocking_enabled이 켜져 있을 때만 가능합니다. 승인 시간이 초과되어 페일오픈이 발생합니다. - EICAR과 같은 테스트 서명은 알림 기록에만 남깁니다 — 업계 표준 테스트 문자열은 알림을 표시하지 않고 알림 기록에만 남기며, fanotify 가드와 다운로드 가드 모두에서 격리되거나 차단되지 않습니다.
- 사용자가 구성한
scan_exclusions경로 목록(절대 경로, 재귀적으로 적용됨, 레거시clamav_exclusions포함)은 YARA 및 ClamAV 스캐너 모두에서 적용됩니다. 프롬프트의 "허용"과 격리 탭의 "복원"이 모두 여기에 추가되므로 동일한 파일에 플래그가 다시 지정되지 않습니다. - 감지 및 확인된 실제 악성코드는
~/.local/share/roamswitch/quarantine/로 재배치되었습니다. 금고는0700입니다. 각 샘플은0400(읽기 전용, 실행 불가능)입니다. 복원 시 파일은0644으로 반환되고 대상 디렉터리의 소유자에게 소유됩니다. - 권한-이벤트 루프는 파일 시스템 I/O을 수행하지 않습니다. — 구성은 전용 백그라운드 스레드에 의해
Mutex<GuardConfig>스냅샷으로 읽혀집니다. 핫패스 접근자는 잠그고 복사하기만 하면 됩니다. 이는 설계 불변입니다.FAN_OPEN_PERM을 차단하면 시스템이 정지됩니다. - ClamAV가 있으면 새로 다운로드한 실행 파일(
.sh,.deb,.elf, …)과 위험한 AI 모델(.pkl,.pt)을 로컬 DB에 대해 검사합니다. ClamAV는 선택적 종속성입니다. 다른 방어는 그것 없이도 작동합니다. 설치되면 일일 업데이트 프로그램(§11)이freshclam을 호출하여 서명 데이터베이스가 최신 상태로 유지됩니다.
커널 로컬 권한 확대(LPE) 선점 및 강화
공격자나 맬웨어가 권한이 없는 사용자의 기반을 확보하면 심층 방어 기능을 통해 Linux 커널 취약점을 악용하여 루트 권한을 얻는 것을 방지합니다.
- 권한 없는 사용자 네임스페이스 비활성화(Frag Gap CVE-2026-53362 완화) — 많은 최신 Linux 커널 LPE 취약점은 권한 없는 사용자가
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을 통해 메모리를 읽는 것을 방지하여 브라우저 세션과 GPG/SSH 개인 키를 보호합니다. - 코어 덤프 억제 —
fs.suid_dumpable = 0을 설정하면 민감한 프로세스가 일반 텍스트 메모리 덤프를 디스크에 기록하지 못해 충돌이 발생하는 것을 방지할 수 있습니다. /tmp&/dev/shmnoexecMount Defense — 페이로드 삭제 및 실행 공격을 방지하기 위해 RoamSwitch는 신뢰할 수 없는 네트워크에 연결할 때noexec,nosuid,nodev을 사용하여/tmp및/dev/shm을 다시 마운트합니다.
eBPF 런타임 위협 센서 및 자율 프로세스 동결(데스크톱 eBPF 가드)
RoamSwitch 클라이언트 데몬에는 커널 내 최신 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 도메인 소켓 IPC(
/var/run/roamswitch/events.sock) — Falco 또는 기타 eBPF 센서의 경고는 디스크 로그에 기록하지 않고 메모리 내 UNIX 소켓을 통해 직접 수신되므로 디스크 I/O 대기 시간이 제거되고 1초 미만의 응답 전달이 가능합니다. - 자율 다층 완화(프로세스 동결 및 Air-Gap) — 우선순위가
Critical또는Emergency인 이벤트(예: 커널 LPE, 네임스페이스 이스케이프 또는 랜섬웨어 실행)가 수신되면 데몬은 문제가 되는 PID에서SIGSTOP를 실행하여 프로세스 실행을 즉시 일시 중지하고(상태:Ts)inet roamswitch전체에policy drop을 배포합니다(Air-Gap). 즉각적인 데스크탑 알림을 트리거합니다. - 데스크톱용 저부하 & 로그 비대화 방지 튜닝(RoamSwitch Optimized) — 노트북과 워크스테이션의 배터리 소모·CPU 부하·디스크 고갈을 억제하기 위해, 최적화 프로필(
99-roamswitch-optimized.yaml)을 기본 제공합니다:- 심각도 필터링(
priority: warning) — 일상적인 알림/정보 이벤트의 95%를 필터링합니다. - Kernel Early Drop(
drop_failed_exit: true) — 실패한 syscall 종료를 커널 드라이버에서 직접 삭제하여 컨텍스트 스위치와 CPU 로드를 절반으로 줄입니다. - 컴팩트 링 버퍼(
cpus_for_each_buffer: 2) — 링 버퍼 크기를 2MB로 줄이고 상주 RAM을 30~50MB로 유지하며 CPU 사용량을 1% 미만으로 유지합니다. - 필수 로그 회전 용량(
/etc/logrotate.d/roamswitch-falco) — 7세대 압축 회전으로 엄격한 50MB 한도를 적용합니다.
- 심각도 필터링(
- 하이브리드 복원력(독립형 대 eBPF 모드) — Falco가 없으면 RoamSwitch는 커널 sysctl(
user.max_user_namespaces = 0), nftables 로밍 프로필, fanotify 엔트로피 추적 및 카나리아를 통해 시스템을 보호합니다. Falco를 사용하면 심층적인 커널 내 행동 원격 측정이 고급 제로데이 익스플로잇을 차단하고 공격자 프로세스를 실시간으로 정지시킵니다.
§6
USB 이벤트가 모니터링됩니다. 키보드급(HID) 장치와 USB 대용량 저장소가 추적됩니다. 기본적으로 꺼짐(출하 isEnabled = false, macOS USBKeyboardGuard / USBStorageGuard과 일치). 첫 실행 마법사 또는 USB 탭에서 선택하세요. 활성화하면 확인 대화 상자가 표시됩니다.
악성 USB 키보드(키스트로크 주입)
- 커널 수준의 물리적 포트 승인 취소 없음(중요). 이전 구현(1.0.6 이하)에서는 등록되지 않은 키보드에 대해
0을/sys/bus/usb/devices/*/authorized에 썼고 물리적으로 연결을 끊었습니다. 결합된 키보드+마우스 수신기(Raspberry Pi 또는 미니 PC에서 일반적)에서는 마우스 연결도 끊어지고 내장 입력이 없는 시스템이 잠깁니다. 이제 RoamSwitch는 HID 인터페이스(bInterfaceClass 03)를 노출하는 모든 장치에authorized=0쓰기를 강력히 거부하고, 데몬은 시작 시 이전 버전이 차단한 시스템을 자가 복구하기 위해 모든authorized==0HID 장치를 다시 인증합니다. - 키 입력은 소프트웨어에서 삭제됩니다. 등록되지 않은 키보드를 감지하면 해당 장치의
/dev/input/eventN에서 독점적인 evdevEVIOCGRAB이 사용됩니다(VID:PID와 일치하는/proc/bus/input/devices에kbd처리기가 있는 노드만 해당). 마우스 노드는 그대로 유지됩니다. 이는 macOSCGEventTap에 해당하는 Linux입니다. 장치에 전원이 계속 공급됩니다. - 안전 — 입력할 다른 키보드(내장 키보드 또는 승인되고 연결된 USB 키보드)가 있는 경우에만 잡기가 수행되므로 새 키보드가 하나 있는 기계는 절대 잠기지 않습니다.
- 승인 대화 상자 — 승인과 함께 승인 요청이
/run/roamswitch/approvals.json에 대기하고 GUI에 모달(허용/거부)이 표시됩니다. 허용은 장치를 화이트리스트에 추가하고 가져오기를 해제합니다. 3분 후 페일오픈.
악성 USB 대용량 저장 장치
등록되지 않은 USB 대용량 저장 장치(HID 인터페이스 없음)를 삽입하고 가드가 활성화되고 네트워크가 신뢰할 수 없거나 잠긴 경우 authorized=0(HID가 아닌 장치에 대해 안전함)으로 유지되고 승인 대화 상자가 표시됩니다. 재승인 및 화이트리스트를 허용합니다. Deny는 이를 유지합니다. macOS 빌드는 1.7.4에서 이 "읽기 전용 보유 + 승인 프롬프트" 모델에 맞춰 조정되었습니다.
식별 및 기득권 부여
HID는 bInterfaceClass == "03" 및 /proc/bus/input/devices의 Handlers= 줄에서 결정됩니다. 콤보 수신기(kbd 및 마우스 섹션이 모두 포함된 하나의 VID:PID)는 VID:PID로 병합됩니다. 데몬 시작 시 존재하는 등록되지 않은 키보드는 할아버지입니다; 나중에 핫 플러그된 키보드만 잡습니다.
§7
roamswitch-core의 LinuxHealthChecker은 24개 항목을 평가하고 0~100점, A~F 등급 및 항목별 조언을 생성합니다. GTK 대시보드에서는 CLI(roamswitch status) 및 MCP(get_security_report)에서 24개 항목 모두의 제목, 세부정보 및 권장 사항이 사용자의 언어(10개 언어)로 표시됩니다.
| 카테고리 | 예시 항목 |
|---|---|
| 디스크 / 부팅 | LUKS / dm-crypt 암호화, UEFI 보안 부팅 |
| 접근 통제 | LSM(AppArmor/SELinux), SSH/sudo 구성 감사 |
| 커널 강화 | sysctl 강화, 권한 없는 사용자 네임스페이스 비활성화(Frag Gap 완화), 코어 덤프 제어, /tmp 및 /dev/shm에 대한 noexec |
| 업데이트 | 자동 보안 업데이트 구성 |
| 네트워크 | ARP 스푸핑 모니터링, 게이트웨이 ARP/NDP 잠금 상태, 노출된 포트 감사, Wi-Fi 암호화 강도 |
| 악성코드 | ClamAV / fanotify(가드가 실제로 실행 중인지 확인) / 엔트로피 모니터링 / noexec |
| 브라우저 | Firefox/Chrome/Chromium 세이프 브라우징 설정 |
| DNS / USB | 위협 방지 DNS, USB 버스의 제로 트러스트 상태 |
모든 검사는 로컬 파일 및 명령 출력(getenforce, mokutil, resolvectl, ss, …) 읽기를 기반으로 합니다. 어떤 종류의 외부 쿼리도 없습니다.
신뢰 인식 등급. RoamSwitch가 신뢰할 수 있는 (홈) 네트워크에 고의적으로 not 적용하지 않도록 강화 — 게이트웨이 MAC를 영구로 고정(라우터 재부팅 시 LAN을 블랙홀하게 함), /tmp 및 /dev/shm noexec 다시 마운트(패키지 빌드 및 일부 설치 프로그램 중단) 및 기본 범위에서 위협 보호 DNS — 빨간색 "강화되지 않음"이 아닌 설명과 함께 녹색으로 표시되며 신뢰할 수 없는 네트워크에서는 자동으로 적용된다는 점을 참고합니다. 런타임 정보는 데몬이 매 주기마다 작성한 /run/roamswitch/state.json(active_level / network_trusted / fanotify_ready)에서 나옵니다. fanotify 항목은 단순히 커널이 지원하는 것이 아니라 가드가 실제로 표시되어 실행 중인지(/run/roamswitch/fanotify.ready) 확인합니다. 노출된 포트 항목은 데몬의 라이브 프로필을 읽습니다(MCP 하드 코드가 사라졌습니다).
항목별 강화. 자동 수정(커널 sysctl/Yama/코어 덤프, /tmp noexec, USB 제로 트러스트, 게이트웨이 ARP 고정, 위협 방지 DNS, fanotify 가드가 다운되었을 때 데몬 다시 시작)이 있는 실패한 항목에는 GTK 대시보드에 "🔧 강화" 버튼이 있습니다. 데몬은 루트로 실행되므로 데몬을 다시 시작하는 것 외에는 pkexec이 필요하지 않습니다.
§8
roamswitch-mcp은 stdio를 통해 JSON-RPC를 사용하며 Claude Desktop, Cursor 및 Antigravity와 같은 AI 클라이언트에 의해 생성됩니다. 모든 도구는 읽기 전용이며 완전히 로컬입니다.
| 도구 | 목적 |
|---|---|
| get_security_report | 24개 항목 평가, 점수, 권장사항 |
| get_exposed_ports | 노출된 포트 및 해당 방화벽 차단 상태 |
| get_guard_status | 현재 보호 수준 및 방어 모듈 상태 |
| audit_url_safety | 경험적 URL 안전성 분석(대상을 가져오지 않음) |
| 감사_비밀 | 텍스트 내 API 키/비밀 감지(텍스트를 전송하지 않음) |
| audit_security_logs | 로컬 저널/인증 로그 집계 |
| get_quarantine_status / get_canary_status | 검역과 카나리아 주 |
| get_app_help | 내장된 지식 베이스 검색 |
| run_active_vuln_scan | 127.0.0.1 한정·비파괴 실증형 취약점 검증. 유일하게 네트워크를 사용하는 도구이며 기본값은 비활성, 설정에서 옵트인이 필요합니다. |
| run_package_cve_scan | 설치된 패키지(Mac: Homebrew / Linux: dpkg・dnf・zypper・pacman)를 로컬 CVE 맵과 대조합니다. 네트워크 통신은 전혀 하지 않습니다. |
| run_package_cve_scan_languages | npm / PyPI / crates.io / RubyGems / Packagist / Go / Maven 등의 의존성 락파일을 동일한 로컬 CVE 맵과 대조합니다. 네트워크 통신은 전혀 하지 않습니다. |
| verify_fim | 약 150곳의 핵심 시스템 파일을 다시 해시하여 베이스라인과 비교해 변조를 검증합니다. |
| get_file_scan_guard_status | 파일 스캔 가드(ClamAV)의 설정과 그것이 사용하는 격리 Vault 상태를 반환합니다. |
| get_port_anomaly_incidents | 포트 이상 가드의 베이스라인 확보 상태, 현재 자동 차단 중인 포트, 최근 50건까지의 인시던트를 반환합니다. 현재 자동 차단 중인 포트는 타임스탬프가 없는 현재 상태의 스냅샷이며, 타임스탬프가 있는 인시던트 이력과는 다르다는 점을 응답 내 주석 필드로 명시하고 있습니다. |
| get_ebpf_incidents | eBPF 런타임 가드의 현재 격리 상태와 발동 사유가 된 인시던트 이력을 반환합니다. |
| get_resource_guard_incidents | 리소스 고갈·프로세스 이상 탐지 가드의 이력(메모리 누수/크래시 루프)을 신뢰도 등급과 함께 반환합니다. |
| get_notification_history | RoamSwitch가 보낸 알림(보안 로그 감사 이상, ClickFix 탐지 등)의 기록을 최근 1주일간, 최신순으로 반환합니다. |
| get_incident_timeline | 각 가드의 탐지를 하나의 시계열로 통합해 반환합니다(프로세스 계보·MITRE ATT&CK 태그 포함, 실험적). |
MCP 서버는 스스로 네트워크를 열지 않습니다. roamswitchkit을 통해 데몬의 Unix 소켓에 연결하거나 roamswitch-core 로직을 직접 호출할 뿐입니다. 유일한 예외는 기본값이 비활성인 run_active_vuln_scan이 127.0.0.1, 즉 호스트 자신에게 보내는 비파괴 프로브입니다.
로컬 LLM 실전 훈련에서 발견된 오귀속 문제와 그 수정
2026년 9월, 이 MCP 서버를 사용해 로컬 LLM(Qwen 3.8 27B)에게 사고 조사를 맡기는 실전 훈련(fire drill)을 진행하던 중, 모델이 get_port_anomaly_incidents가 반환하는 데이터를 잘못 해석하여 무관한 과거의 포트 차단 기록을 현재 진행 중인 사고의 서사에 끌어들이는 사례를 발견했다. 원인은 타임스탬프가 없는 '현재 차단 중인 포트'의 스냅샷과, 타임스탬프가 있는 실제 사고 이력이 같은 응답 안에서 구분 없이 반환되고 있었기 때문이다. 수정 사항으로, 어느 쪽이 시계열 데이터이고 어느 쪽이 스냅샷인지를 명시하는 주석 필드를 추가했다. 수정 후 동일한 시나리오를 같은 모델로 다시 실행한 결과, 모델은 주석의 문구를 인용하며 과거의 포트를 현재 사고에 귀속시키는 것을 명시적으로 거부했다. 자동 회귀 테스트와 실제 LLM 재현 확인 양쪽에서 수정의 효과를 검증했다.
§9
Linux용 RoamSwitch는 정확히 한 종류의 아웃바운드 요청, 즉 서명된 매니페스트의 일일 업데이트 프로그램의 GET을 만듭니다(§11). 그 밖의 모든 평가, 탐지, 감사 등 모든 작업은 로컬에서 완료됩니다. Linux용 RoamSwitch는 독점 프리웨어이며 해당 소스는 공개되지 않습니다. 따라서 아래 검사는 lafine에서 수행했습니다. 결과는 9.2에 있으며 부록 C의 단계는 배포된 패키지에서만 재현 가능합니다.
9.1 감사방법
- 크레이트 격리 — HTTP/TLS 스택은 하나의 크레이트에서만 허용됩니다,
roamswitch-updater. 이는 독립 실행형 타이머 기반 업데이터 바이너리를 빌드합니다.scripts/audit_no_network.sh(CI에서 실행, 게이팅)은roamswitch-core,roamswitch-daemon,roamswitch-app,roamswitch-mcp또는roamswitchkit이reqwest/hyper/ureq/rustls/native-tls/openssl을 가져오거나roamswitch-updater외부의.rs파일이TcpStream/를 사용하는 경우 빌드에 실패합니다.TcpListener/UdpSocket/to_socket_addrs/lookup_host. - 종속성 트리 검사 — 전체
Cargo.lock이 원격 측정/분석/충돌 보고 SDK(sentry,opentelemetry, …)에 대해 검색되었습니다. roamswitch-updater검토 — 단일 요청 대상, 쿼리 문자열/쿠키/식별 헤더의 부재 및 다운로드하는 모든 항목에 대한 Ed25519 확인.- 하위 프로세스 열거 — 모든
Command::new(...)호출 사이트가 검토되었습니다.
9.2 결과
| 감사항목 | 결과 |
|---|---|
| HTTP/TLS 스택 | roamswitch-updater에만 (ureq + rustls)에만 존재합니다. core / daemon / app / mcp / kit에는 없음 |
| 원격 측정/분석/충돌 보고 SDK | 존재하지 않음 어디에도 없음 |
TcpStream / TcpListener / UdpSocket | 한 번도 발생하지 않음 roamswitch-updater 외부 |
| 사용 중인 소켓 API | AF_UNIX(로컬 IPC); AF_NETLINK(NFQUEUE 판정 채널, nftables 및 ip neigh 제어 - 송신 없음) AF_INET 만(roamswitch-updater). 활성화된 VPN 터널(§4)은 wg-quick(WireGuard 백엔드) 또는 tailscaled(Tailscale 백엔드)입니다. 이는 데몬이 아닌 하위 프로세스로, 사용자의 엔드포인트/tailnet으로 트래픽을 보냅니다. |
| 일일 업데이터 | ~24시간당 하나의 GET https://lafine.net/updates/v1/manifest. 쿼리 문자열 없음, 쿠키 없음, 일반 사용자 에이전트, 식별자 없음. 모든 페이로드는 Ed25519 인증을 받았습니다. updates.enabled = false은 완전히 비활성화합니다. |
| VPN 터널(§4) | 기본적으로 꺼져 있습니다. 활성화되면 wg-quick은 Lafine과 관련되지 않은 사용자 자신의 .conf에 있는 엔드포인트 에 WireGuard 터널을 구축합니다. Rust 소켓 API가 아닌 getent ahosts(glibc NSS)를 통한 엔드포인트 호스트 이름 확인 |
| 라이선스 활성화 | 오프라인 Ed25519 서명 확인. 활성화 서버와 통신하지 않음 |
Linux용 RoamSwitch는 정확히 한 종류의 아웃바운드 요청, 즉 사용자나 시스템에 대한 정보를 전달하지 않는 서명된 탐지 데이터를 매일 수신 전용으로 다운로드하는 요청을 시작합니다. 제품의 다른 어떤 것도 외부 서버와 연결되지 않습니다.
9.3 외부 대면 작업의 전체 목록
패킷이 직접 또는 간접적으로 로컬 시스템을 떠나게 할 수 있는 모든 작업은 다음과 같습니다.
| # | 작동 | 목적지 | 트리거 | 전송되는 내용 |
|---|---|---|---|---|
| 1 | Daily updater — GET /v1/manifest 및 버전 변경 시 피드 파일 | lafine.net/updates/v1(CDN) | systemd 타이머, ~24시간마다 한 번씩 무작위 지연이 발생합니다. updates.enabled = false 또는 roamswitch-update.timer이 비활성화되면 꺼짐 | 일반 HTTPS GET: 쿼리 문자열 없음, 쿠키 없음, 일반 User-Agent, 사용자 또는 시스템에 대한 정보 없음. 서명된 매니페스트 + 피드 수신 |
| 1a | freshclam(ClamAV 자체 업데이트 프로그램), ClamAV가 설치될 때 일일 업데이트 프로그램에 의해 호출됩니다. | ClamAV 프로젝트의 CDN | #1의 일부로 | ClamAV 자체의 트래픽(별도 프로젝트) RoamSwitch만 실행합니다. |
| 2 | ping -c1 -W1 <게이트웨이 IP> | LAN 기본 게이트웨이(링크-로컬) | ARP 스푸핑 감지 중에 ARP 캐시를 새로 고치려면 | ICMP 에코 요청만 가능합니다. DNS 확인 없음, 페이로드 없음 |
| 3 | 시스템 브라우저 실행(xdg-open) | https://lafine.net/...(제품 사이트) | 사용자가 '릴리스 노트 열기'와 같은 버튼을 클릭하는 경우에만 | RoamSwitch 프로세스는 소켓을 열지 않습니다. OS 브라우저에 URL을 전달합니다. |
| 4 | resolvctl dns | — (통신이 발생하지 않음) | 신뢰할 수 없는 네트워크의 위협 방지 DNS(선택). <iface>은 기본 경로(유선 + 무선 동시, lo / tailscale* / wg* / docker* / veth* 제외)를 전달하는 모든 물리적 NIC입니다. dns_scope = always_on일 때 신뢰할 수 있는 네트워크에도 적용됩니다. 모든 감시 주기를 조정했습니다. | OS 확인자 설정만 변경합니다. RoamSwitch 자체는 DNS 쿼리를 보내지 않습니다. |
| 5 | 패키지 관리자 업데이트 | 배포판의 apt / dnf / zypper 저장소 | 사용자 이 apt upgrade 등을 실행하거나 GUI "지금 업그레이드" 버튼(pkexec을 통해 apt-get / dnf / zypper 실행)을 클릭할 때 | RoamSwitch는 로컬 apt-cache policy 출력을 읽고 패키지 관리자를 시작합니다. 라핀과 무관 |
| 6 | VPN 터널(§4) — WireGuard 백엔드: 터널 wg-quick 빌드/Tailscale 백엔드: tailscale set --exit-node은 출구 노드를 통해 모든 트래픽을 라우팅합니다. | 사용자 자신의 VPN 엔드포인트 / tailnet(WireGuard: .conf의 엔드포인트, Tailscale: 선택한 종료 노드 및 DERP 릴레이) | vpn_on_untrusted_enabled 및 네트워크를 신뢰할 수 없는 경우. 기본적으로 꺼짐 | 암호화된 WireGuard/Tailscale 트래픽; 목적지는 라피네와 무관한 사용자 본인의 VPN 서버/테일넷입니다. getent ahosts(glibc NSS)을 통한 WireGuard 엔드포인트 확인; Tailscale은 tailscaled(별도의 프로세스)에 의해 구동됩니다. |
다른 모든 RoamSwitch 기능 — nftables 제어, 이웃 테이블의 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 서버에는 쿼리가 수행되지 않습니다.
- 충돌 보고 없음 — 패닉 상태에서는 스택 추적이 어디에도 전송되지 않습니다.
- 일일 업데이트 프로그램은 귀하에 대해 아무것도 보내지 않습니다 — 쿼리 문자열, 쿠키, 장치 또는 설치 식별자, 일반
User-Agent이 없습니다. 보고서가 아닌 다운로드입니다. 링크 가드 판정, 차단된 호스트 및 검색 결과는 로컬 활동 보기/저널에만 기록되며 전송되지 않습니다.
§11
| 에디션 | 에 대한 | 가격 | 라이센스 |
|---|---|---|---|
| 커뮤니티 에디션 | 리눅스 개인용 | 무료 | 독점 프리웨어(번들 EULA) |
| 비즈니스(예정) | 차량 관리, 정책 배포, 서명된 내부 아파트, 조직을 위한 SLA | 유료 | 상업용 라이센스. 동일한 바이너리 + 계층 게이트 |
macOS RoamSwitch Pro Lifetime 구매자는 자신의 Linux 시스템에서 비즈니스 기능을 무료로 받을 수 있습니다.
유통 및 공급망
| 채널 | 세부정보 |
|---|---|
| 아파트 | https://lafine.net/apt (stable main). Release는 RSA-4096 키로 서명되었습니다. |
| RPM | https://lafine.net/rpm(Fedora/openSUSE 별도). repomd.xml GPG 서명 |
| AUR | roamswitch-bin(GitHub 릴리스 tarball 가져오기, sha256 확인) |
| 타르볼 | GitHub 릴리스의 amd64 / aarch64 .tar.gz + .sha256 |
- 고정된 glibc 바닥 — 릴리스 바이너리는 Debian 12(bookworm, glibc 2.36) 컨테이너 내부에 구축되었습니다. 이는 Debian 12/Ubuntu 22.04 이상에서 기호 버전 불일치를 방지합니다. 2.36 이상을 요구하는 종속성이 도입되면 "glibc 바닥 확인" CI 단계가 빌드에 실패합니다.
- 서명 키 관리 — apt/rpm 저장소 서명을 위한 개인 키는 GitHub Actions 암호화된 비밀에만 존재합니다. 공개 키만 저장소에 커밋됩니다.
11.3 일일 업데이트
roamswitch-updater은 systemd 타이머(임의로 3시간 지연되는 roamswitch-update.timer, OnCalendar=daily 및 Persistent=true)에 의해 실행되는 독립 실행형 바이너리입니다. 네트워크에 도달하는 유일한 구성요소입니다. 각 실행:
GET https://lafine.net/updates/v1/manifest및 해당 분리된 서명.- Sparkle 앱 업데이트 키와 별도로 전용 위협 피드 서명 키를 사용하여 매니페스트의 Ed25519 서명을 확인하세요. 피드는 서버 측 CI에 의해 매일 다시 서명되므로 개인 키는 CI 비밀에 보관됩니다. 범위를 피드로 지정한다는 것은 유출로 인해 공격자가 잘못된 차단 목록(싱크홀/경고 - 코드 경로 없음, 앱 업데이트 경로 없음)만 제공할 수 있음을 의미합니다. 앱 업데이트 서명 키는 macOS 키체인을 벗어나지 않습니다. 확인되지 않은 매니페스트는 삭제됩니다. 업데이트 프로그램은 서명되지 않은 데이터로 대체되지 않습니다.
- 위협 피드 버전이 변경된 경우 피드를 다운로드하고 SHA-256 및 Ed25519 서명을 확인한 후 링크 가드에 대해 원자적으로 설치합니다(§4).
- ClamAV가 설치된 경우
freshclam을 호출합니다. - 알림을 위한 최신 앱 버전을 기록합니다(업데이터 never는 앱을 설치하지 않습니다. Linux에서는 사용자가
apt upgrade을 실행합니다).
모든 단계의 실패(오프라인, 잘못된 서명, freshclam 누락)는 updates.lastError로 기록되고 프로세스는 여전히 0으로 종료되므로 타이머 실행은 시스템 실패 알림을 생성하지 않습니다. 전체 메커니즘은 updates.json의 updates.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 64-bit (Bookworm), Ubuntu for Raspberry Pi
- 아키텍처: x86_64 / aarch64
- 필수:
systemd,nftables,iproute2(ip neigh— ARP/NDP 잠금) (.deb/.rpm종속성에 의해 자동으로 가져옴) - 선택 사항:
clamav(맬웨어 검색),nmcli(Wi-Fi 암호화 감지),libnotify(데스크톱 알림),wireguard-tools(VPN 터널의 WireGuard 백엔드 + 킬 스위치, §4),tailscale(Tailscale 백엔드, §4),polkit/pkexec(GUI에서 업그레이드 실행) - 지원되지 않음: 시스템화되지 않은 배포판(Alpine / Void / Devuan)
- 디스플레이: 1280×720 이상(창 및 글꼴은 화면 크기에 맞게 자동 조정되며 소형 Raspberry Pi 디스플레이 지원)
부록 A
| 상자 | 목적 | 네트워크 |
|---|---|---|
| serde / serde_json | 구성 및 IPC 직렬화 | 없음 |
| 토키오 | 비동기 런타임(features = ["full"], 그러나 Unix 소켓만 사용됨) | 없음(TCP 없음) |
| 추적 / 추적 구독자 | 로깅(로컬/저널링) | 없음 |
| 이 오류 / 어쨌든 | 오류 처리 | 없음 |
| 정규식 | 문자열 구문 분석(진단, CSS 크기 조정) | 없음 |
| URL | URL 구문 분석(audit_url_safety 경험적 방법) | 없음(가져오지 않음) |
| 크로노 | 날짜/시간 처리 | 없음 |
| ed25519-달렉 | 라이센스 서명 오프라인 확인 | 없음 |
| base64 / sha2 | 라이센스 토큰, 카나리아 해시 | 없음 |
| libc | chown / kill / 시스템콜 | 없음 |
| 이드나 | 동형이의어 감지를 위한 IDN/퓨니코드 호스트 디코딩 | 없음 |
| nfq(데몬 전용) | 링크 가드를 위한 NFQUEUE 바인딩 — 순수 Rust, AF_NETLINK | 없음(판정 채널, 송신 없음) |
| 열다 | "공개 릴리스 노트"에 대해 xdg-open을(를) 호출합니다. | 프로세스 자체는 통신하지 않습니다. |
| GTK3 / ksni(앱 전용) | GUI 및 트레이 | 없음 |
| ureq + Rustls(roamswitch-updater 전용) | 일일 업데이터의 하나인 HTTPS GET | 트리의 유일한 HTTP/TLS 스택입니다. 업데이터 바이너리로 제한됨 |
roamswitch-core, roamswitch-daemon, roamswitch-app, roamswitch-mcp 또는 roamswitchkit에는 HTTP 클라이언트, TLS 스택 또는 원격 측정 SDK가 표시되지 않습니다. ureq + rustls은 roamswitch-updater에만 존재합니다(scripts/audit_no_network.sh은 이를 CI에서 시행합니다). 원격 측정 SDK는 어디에도 없습니다.
부록 B
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 확인자(§4)의 ARP/NDP 고정은 nftables가 아닌 커널 인접 테이블(ip neigh replace … nud permanent)에서 에서 수행됩니다. 고정된 항목은 /var/lib/roamswitch/arp_lock.json에 기록됩니다.
부록 C
이 문서의 모든 주장은 귀하의 컴퓨터에서 확인할 수 있습니다. 아래 명령은 roamswitch 패키지가 설치된 호스트에서 실행됩니다.
C.1 아웃바운드 트래픽 확인
데몬/앱/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 인터넷 연결이 하나도 없음
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을 한 번만 수행한 뒤 종료합니다.
해제하고 완전히 침묵을 확인하세요:
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개 항목) 은 공개 지원 저장소에서 제공되는 공식 Docker 테스트 제품군을 사용하여 호스트 네트워크나 파일에 영향을 주지 않고 격리된 컨테이너에서 100% 안전하게 재현 및 검증될 수 있습니다. (roamswitch 지원
# 검증 스위트 가져오기 및 재현 실행(공식 배포 패키지를 사용해 격리된 컨테이너 내에서 자동 검증)
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 Self-Healing
| 아이디 | 시나리오 | 검증방법 | 합격 기준 |
|---|---|---|---|
| SP-3 | Air-Gap 활성화 → 송신 중단 | enable_air_gap IPC 보내기 | policy drop은 출력 후크에 적용됩니다. 모든 아웃바운드 트래픽이 차단됨 |
| SP-3b | 방화벽 강제 제거 및 자가 복구 | nft delete table inet roamswitch을 통한 제거 규칙 | Anti-Clobber 자가 치유 기능은 5초 이내에 드롭 규칙을 복원합니다. |
| SP-3c | 데몬 재시작 시 페일클로즈됨 | Air-Gap 중간에 하드 킬 데몬(SIGKILL) 및 재시작 | 송신 삭제 정책은 다시 시작해도 원활하게 유지됩니다. |
| SP-3d | 승인된 Air-Gap 복구 | 승인된 disable_air_gap IPC 보내기 | 삭제 정책 해제, 모든 마커 파일 제거, 송신 복원 |
| SP-8 | 예방적 ARP/NDP 고정 | 격리된 netns 게이트웨이 환경에서 활성화 → 스푸핑된 무상 ARP 전송 | 게이트웨이 인접 항목은 PERMANENT로 유지됩니다. 스푸핑된 ARP가 무시됨 |
| SP-9 | VPN 킬 스위치(WireGuard) | 별도의 netns에 있는 Live WireGuard 서버, .conf → vpn_up 가져오기 | 핸드셰이크는 inet roamswitch_vpn을 통해 완료됩니다. 터널 사망 시 누출 없음 |
| SP-10 | VPN 킬 스위치(Tailscale) | 스텁 tailscale CLI + 별도의 netns, tailscale0 IF | 터널 외부 일반 텍스트 TCP/80 및 로컬 DNS가 차단되었습니다. DERP 및 MagicDNS 허용 |
(2) 커널 및 마운트 강화
| 아이디 | 시나리오 | 검증방법 | 합격 기준 |
|---|---|---|---|
| SP-11a | 네트워크 sysctl 강화 | apply_kernel_sysctl_hardening IPC 실행 | rp_filter=1, tcp_syncookies=1, accept_redirects=0 목표 값에 도달 |
| SP-11b | 메모리 보호 및 Yama LSM | ptrace_scope 및 suid_dumpable 확인 | kernel.yama.ptrace_scope=1(스누핑 차단), fs.suid_dumpable=0(코어 덤프 없음) |
| SP-11c | /tmp 및 /dev/shm noexec 방어 | apply_mount_hardening IPC 실행 | /tmp 및 /dev/shm이 noexec,nosuid,nodev을(를) 다시 마운트했습니다. 실행이 거부됨 |
| SP-11d | 합법적인 사용자 실행이 보존됩니다. | 표준 홈 디렉터리(~/)에서 스크립트 실행 | 합법적인 개발자/관리자 작업 흐름을 방해하지 않고 방해 없이 실행됩니다. |
(3) 다층 악성코드 및 랜섬웨어 방어 및 카나리아
| 아이디 | 시나리오 | 검증방법 | 합격 기준 |
|---|---|---|---|
| SP-1 | 카나리아 변조 감지 | ~/Documents/에서 미끼 카나리아 파일(.xlsx)을 자르거나 이름을 바꿉니다. | 몇 초 안에 변조가 감지되어 즉각적인 Air-Gap이 발생합니다. |
| SP-2 | 랜섬웨어 대량 암호화 버스트 감지 | 단일 프로세스로 여러 개의 고엔트로피 파일을 빠르게 생성 | SIGSTOP로 인해 위반 작업자 프로세스가 정지되었습니다. Air-Gap이 트리거됨 |
| SP-2b | shred에는 거짓양성이 없습니다. | 테스트 파일 전체에서 shred -n 3 -u 실행 | 허용 목록 일치로 오탐지 감지 또는 정지 방지 |
| SP-2c | 중요한 프로세스는 동결되지 않습니다. | 버스트 감지 중 동결 대상 논리 검증 | 중요 데몬(dockerd, systemd, containerd)은 동결되지 않습니다. |
| SP-4 | EICAR 테스트 문자열은 알림 전용입니다. | ~/Downloads/에 EICAR 테스트 문자열 쓰기 | 알림 없이 알림 기록에만 남습니다. 파일은 자동으로 격리되지 않습니다. |
| SP-4b | 실제 악성코드 서명 확인 우선 | 감시 폴더 외부에 실제 서명 쓰기 | 모달 승인 대화 상자를 표시합니다. 사용자 확인 시에만 격리 |
| SP-4c | 검역소 권한 강화 | Vault 디렉터리 및 샘플 파일의 권한 검사 | 0700로 설정된 Vault 디렉터리, 0400로 설정된 격리된 샘플 |
| SP-4d | 권한 있는 IPC 안전 원본 파일 복원 | restore_quarantine_file IPC 보내기 | 파일이 사용자 권한(0644)으로 원래 경로로 복원되고 제외 항목에 추가되었습니다. |
(4) 패시브 링크 가드 및 피싱 방어
| 아이디 | 시나리오 | 검증방법 | 합격 기준 |
|---|---|---|---|
| SP-7 | mode = block 강력한 집행 | 피드 목록 또는 blocklistExtra 호스트에 연결 | TLS 레이어에서 삭제됨(SNI 구문 분석됨) 목록에 없는 안전한 호스트가 HTTP 200에 도달함 |
| SP-7b | mode = warn 페일클로즈 보류 | 사용자 응답 없이 경고 호스트에 연결(시간 초과 8초) | 시간 초과 시 패킷을 삭제합니다(fail-closed). 명시적인 승인이 있는 경우에만 허용됨 |
| SP-7c | mode = off 완전 분해 | 링크 가드 비활성화 | inet roamswitch_linkguard 테이블이 완전히 제거되었습니다. |
(5) BadUSB 완화 및 장치 제어
| 아이디 | 시나리오 | 검증방법 | 합격 기준 |
|---|---|---|---|
| SP-6 | 연결된 키보드 할아버지 | 데몬 시작 시 연결된 키보드 확인 | 기존 장치는 유효합니다. 후속 핫플러그만 확보됨 |
(6) Docker 환경의 침투 테스트 스위트(17개 점검)
| 아이디 | 공격 벡터 | 시뮬레이션 세부정보 | 방어/탐지 기준 |
|---|---|---|---|
| 펜트-1 | C2 유출 | Air-Gap에서 C2로의 송신 HTTP/TCP 시도 | 모든 패킷은 netfilter에서 삭제됩니다. 누출 제로 |
| 펜트-1b | FW 강제 삭제 | nft delete table inet roamswitch을(를) 사용한 제거 규칙 | Anti-Clobber 자가 치유 기능으로 몇 초 내에 규칙을 복원합니다. |
| 펜트-1c | Air-Gap 안전 복원 | 인증된 disable_air_gap IPC 발행 | 삭제 규칙이 제거되었습니다. 마커가 삭제되었습니다. 연결이 복원되었습니다 |
| 펜트-2 | /tmp 백도어 | /tmp에서 삭제된 백도어 스크립트 실행 | noexec 마운트 보호(Permission denied)에 의해 거부됨 |
| 펜트-2b | /dev/shm 공유 메모리 | /dev/shm에 배치된 바이너리 페이로드 실행 | noexec 마운트 방어에 의해 차단됨 |
| 펜트-2c | 사용자 공간 보존 | 합법적인 사용자 디렉터리(/home/tester/)에서 스크립트 실행 | 방해받지 않는 실행; 작업흐름 중단 제로 |
| 펜트-3 | ptrace 메모리 스누핑 | 비밀/토큰 추출을 목표로 하는 PTRACE_ATTACH | Yama LSM kernel.yama.ptrace_scope=1에 의해 거부됨 |
| 펜트-3b | 코어 덤프 비밀 스크래핑 | 메모리 코어 덤프를 얻기 위해 프로세스 충돌을 유발합니다. | fs.suid_dumpable=0에 의해 방지됨 |
| 펜트-4 | 카나리아 변조 | ~/Documents/의 제로아웃 카나리아 미끼 파일 | 크기 이상 및 해시 변화 실시간 감지 |
| 펜트-4b | 카나리아 대량 삭제 | 카나리아 미끼 파일 대량 삭제 | 파일 사라짐 즉시 감지해 사건 제기 |
| 펜트-5 | IP 주소 스푸핑 | 스푸핑된 소스 IP로 패킷 전송 | rp_filter=1(역방향 경로 필터)에 의해 삭제됨 |
| 펜트-5b | SYN 폭주 DoS | 반개방 TCP 연결 플러드 | tcp_syncookies=1에 의해 보호되는 상태 테이블 |
| 펜트-5c | ICMP 경로 하이재킹 | 가짜 ICMP 리디렉션 패킷 삽입 | accept_redirects=0로 인해 무시되었습니다. |
| 펜트-6 | 키릴 문자 동음이의어 피싱 | gооgle.com(키릴 동형이의어)로 이동합니다. | LinkGuard에 의해 식별됨, 점수 40(위험/블록) |
| 펜트-6b | 원시 IP 및 일반 텍스트 트래픽 | 원시 IP에 대한 직접 아웃바운드 연결 | 안전 위험 요인으로 정확하게 표시됨 |
| 펜트-7 | OpenAI API 키 유출 | 코드 또는 로그에 sk-proj-... 토큰 노출 | Shannon 엔트로피 분석을 통해 감지 및 마스크 처리 |
| 펜트-7b | GitHub 토큰 유출 | 코드에 ghp_... 개인 토큰 노출 | 토큰 패턴과 엔트로피 검증으로 일치 |
| 펜트-8 | 커널 LPE(Frag Gap) 선점 | 권한이 없는 unshare -U -r(CVE-2026-53362 시도) | user.max_user_namespaces = 0(Operation not permitted)에 의해 즉시 거부됨 |
| 펜트-9 | eBPF 위협 센서 및 프로세스 정지 | Falco eBPF 소켓을 통해 주입된 중요/긴급 경고 | 밀리초 내에 SIGSTOP을 통해 프로세스가 정지되었습니다(상태: Ts). Air-Gap 배포 |
(7) 침투 테스트 요약(독립형 강화 vs. eBPF 강화)
격리된 Docker 환경에서 실행된 전체 침투 테스트의 결과 요약(대상: RoamSwitch Client Edition이 포함된 Ubuntu 24.04, 공격자: Nmap/curl/hping3, 공식 보고서 docs/CLIENT_PENTEST_REPORT.ja.md 참조):
| 검증항목 | Falco 없음(독립형 강화) | Falco 사용(eBPF 강화) | 국방 평결 |
|---|---|---|---|
| 외부 포트 스캔 저항(Nmap SYN) | PASS(100% 필터링됨 / Lockdown에서 삭제) | PASS(100% 필터링됨 / Lockdown에서 삭제) | 완전한 외부 스텔스 |
| 외부 직접 액세스 차단(TCP/80, 3306) | PASS(시간 초과 감소/0 응답) | PASS(시간 초과 감소/0 응답) | 인바운드 노출 제로 |
| 커널 LPE(프래그 갭) 완화 | PASS (sysctl을 통해 차단된 unshare) | PASS(eBPF 경고 + SIGSTOP 동결 + Air-Gap) | 심층방어 검증됨 |
| 무단 포트 감지(비정상) | PASS (0.0.0.0 바인드 플래그가 높음 위험) | PASS (0.0.0.0 바인드 플래그가 높음 위험) | 100% 감지 및 유도 |
| 로그 팽창 및 CPU 오버헤드 방지 | 제로 로그 공간(제거됨) | PASS (95% 노이즈 컷 / 2MB 버퍼 / 50MB 캡) | 데스크톱 최적화 |
C.3 알려진 제한사항
| 한계 | 영향 | 완화 |
|---|---|---|
일부 커널에서는 tmpfs(/tmp)의 FAN_MARK_MOUNT이 이벤트를 전달하지 않습니다. | /tmp 아래의 파일 쓰기는 fanotify에 의해 모니터링되지 않습니다. | /tmp은(는) 임시 폴더이며 모니터링되는 사용자 폴더가 아닙니다. 랜섬웨어는 ~/을 목표로 합니다. 표시 실패는 명시적으로 기록됩니다. |
| 컨테이너 오버레이fs/tmpfs에서는 fanotify 전달이 없습니다. | 컨테이너 내 엔트로피 버스트 감지를 검증할 수 없습니다. | 실제 하드웨어(ext4)에서 검증되었습니다. 프로브를 통해 하네스 자동 건너뛰기 |
RoamSwitch의 nftables 작업은 Docker의 iptables-nft과 netfilter 공간을 공유합니다. | RoamSwitch 규칙 작업은 Docker의 NAT 규칙을 방해할 수 있습니다. | 운영상의 주의 사항으로 문서화되었습니다. 전용 inet roamswitch 테이블에 격리되지만 nft flush ruleset과 같은 전체 규칙 집합 작업은 피해야 합니다. |
| 링크 가드는 TLS SNI를 통해서만 브라우저의 DoH를 확인합니다. ECH(Encrypted Client Hello)는 이를 숨깁니다. | ECH가 널리 배포되면 ECH 지원 사이트에 대한 ECH 사용 연결을 호스트 이름으로 식별할 수 없습니다. | 로컬 차단 목록과 휴리스틱은 여전히 DNS/HTTP 및 비 ECH TLS에 적용됩니다. DNS 위협 보호(§4.5, 옵트인)는 확인자 경로를 포함합니다. |
일일 업데이터의 최신성은 updates.enabled = false일 때 릴리스 주기에 따라 달라집니다. | 업데이트를 끄면 피드는 마지막 apt upgrade만큼만 최신 상태가 됩니다. | 심각도가 가장 높은 탐지(브랜드 동형이의어)에는 피드가 필요하지 않습니다. 항상 최신 범위를 유지하려면 다시 선택하거나 위협 방지 DNS를 활성화하세요. |