Skip to content

系統架構

本文件詳細說明 SimNet 的系統架構,涵蓋技術棧(Tech Stack)、元件(Component)階層、資料流(Data Flow)與主題系統。

1. 技術棧總覽

層級技術角色
靜態網站產生器VitePress 2.0 (SSG)將 Markdown 內容轉為靜態網頁,支援自訂 Layout(版面配置)
UI 框架Vue 3 Composition API響應式(Reactive)UI 元件系統
樣式系統Tailwind CSS 4.2Utility-first CSS 框架,搭配 CSS custom properties(CSS 自訂屬性)實作主題切換
模擬引擎Rust / WebAssembly (WASM)網路協定模擬核心,編譯為 WASM 在瀏覽器中執行
終端機xterm.js 6.0瀏覽器內嵌終端機模擬器,提供 CLI 互動介面
拓撲圖Canvas 2D網路拓撲(Topology)視覺化渲染

2. 架構圖

┌─────────────────────────────────────────────┐
│              VitePress (SSG)                 │
│  ┌────────┐  ┌──────────┐  ┌─────────────┐  │
│  │ Layout │→ │ SimNet   │→ │ Resizable   │  │
│  │  .vue  │  │  .vue    │  │ Panel .vue  │  │
│  └────────┘  └────┬─────┘  └──────┬──────┘  │
│                   │               │          │
│    ┌──────────────┼───────────────┤          │
│    ▼              ▼               ▼          │
│  Topology    TrafficLog      Terminal        │
│  (Canvas2D)  (Vue DOM)      (xterm.js)       │
│    │              │               │          │
│    └──────────────┼───────────────┘          │
│                   ▼                          │
│           useSimulation.ts                   │
│           useTerminal.ts                     │
│                   │                          │
│                   ▼                          │
│         ┌─────────────────┐                  │
│         │  WASM Bridge    │                  │
│         │  (simnet_wasm)  │                  │
│         └────────┬────────┘                  │
└──────────────────┼───────────────────────────┘

         ┌─────────────────┐
         │  Rust Engine    │
         │  (simnet-core)  │
         │  Protocols, Sim │
         └─────────────────┘

架構說明

上層:VitePress + Vue 元件

  • Layout.vue 是全域進入點,偵測 frontmatter 中的 layout: challenge 來決定是否啟用挑戰模式
  • ChallengeLayout.vue 組裝 SimNet.vue,將 Markdown 內容注入 #mission slot(插槽)
  • SimNet.vue 是核心容器,負責初始化模擬引擎並透過 provide/inject(提供/注入)機制將引擎實例與封包資料傳遞給子元件

中層:Composable 邏輯層

  • useSimulation.ts — 管理 WASM 引擎生命週期、requestAnimationFrame 迴圈、封包正規化(Normalization)
  • useChallenge.ts — 載入挑戰設定、管理狀態機(loading → running → completed)、處理 Flag 驗證
  • useTerminal.ts — 將 xterm.js 與 WASM 引擎命令橋接,提供 CLI 互動

底層:Rust WASM 引擎

  • 以 JSON 格式的 config 初始化,模擬網路拓撲、協定行為與事件系統
  • 透過 wasm-bindgen 匯出 SimNetEngine class 供 JavaScript 呼叫

3. 目錄結構

network-sim/
├── .vitepress/
│   ├── theme/
│   │   ├── layouts/
│   │   │   ├── Layout.vue              # 全域 Layout — 偵測挑戰頁面
│   │   │   └── ChallengeLayout.vue     # 挑戰專用 Layout — 全螢幕模擬器
│   │   ├── components/
│   │   │   ├── SimNet.vue              # 核心容器 — 初始化引擎、provide 資料
│   │   │   ├── ResizablePanel.vue      # 可拖曳調整大小的面板系統
│   │   │   ├── TopologyView.vue        # Canvas 2D 網路拓撲圖
│   │   │   ├── TrafficLog.vue          # 封包流量日誌(Vue DOM 渲染)
│   │   │   ├── Terminal.vue            # xterm.js 終端機元件
│   │   │   ├── IconBar.vue             # 側邊功能列
│   │   │   ├── IconBarPanel.vue        # 功能列展開面板
│   │   │   ├── FlagSubmit.vue          # Flag 提交表單(導覽列嵌入)
│   │   │   ├── DeviceModal.vue         # 裝置詳情彈窗
│   │   │   └── ChallengeSidebar.vue    # 挑戰列表側邊欄
│   │   ├── composables/
│   │   │   ├── useSimulation.ts        # WASM 引擎管理 + RAF 迴圈
│   │   │   ├── useChallenge.ts         # 挑戰狀態機 + Flag 驗證
│   │   │   ├── useTerminal.ts          # 終端機命令橋接
│   │   │   ├── useBreakpoint.ts        # 響應式斷點偵測
│   │   │   └── injectionKeys.ts        # Vue provide/inject Symbol Keys
│   │   ├── loaders/
│   │   │   └── challenge.data.ts       # VitePress data loader — 建置時載入挑戰資料
│   │   ├── styles/
│   │   │   ├── animations.css          # 動畫定義
│   │   │   └── vitepress-overrides.css # VitePress 預設樣式覆寫
│   │   ├── style.css                   # SimNet 色彩系統(CSS custom properties)
│   │   └── index.ts                    # 主題進入點
│   └── types/
│       └── wasm.d.ts                   # WASM 模組型別宣告
├── docs/
│   ├── index.md                        # 首頁
│   ├── challenges/
│   │   ├── index.md                    # 挑戰列表頁
│   │   ├── flags.secret.yaml           # Flag 明文(不進版控)
│   │   └── 01-ethernet-basics/         # 範例情境
│   │       ├── index.md                # Markdown 頁面(frontmatter 指定 layout)
│   │       └── config.yaml             # 拓撲、事件、Flag 設定
│   └── public/
│       └── wasm/                       # 編譯後的 WASM 產物
│           ├── simnet_wasm.js          # JS glue code
│           ├── simnet_wasm_bg.wasm     # WASM binary
│           └── simnet_wasm.d.ts        # TypeScript 型別定義
├── simnet-engine/                      # Rust workspace
│   └── crates/
│       ├── simnet-core/                # 核心型別:Device、Frame、Protocol、Event
│       ├── simnet-devices/             # 裝置實作:PC、Switch、Server
│       ├── simnet-protocols/           # 協定實作:Ethernet、ARP、IPv4、TCP、HTTP
│       ├── simnet-sim/                 # 模擬引擎:Topology、Simulation、EventEngine
│       ├── simnet-crypto/              # 加密模組:Flag 加密與驗證
│       └── simnet-wasm/                # WASM 橋接層:wasm-bindgen API
└── tests/                              # Vitest 測試

4. 資料流

以下說明模擬引擎在每一個 tick(時鐘週期)中如何驅動整個系統。

一次 tick 的完整流程

 requestAnimationFrame 迴圈


  engine.tick()           ← 呼叫 WASM:推進模擬一個時鐘週期


  engine.get_new_packets() ← 取得本次 tick 產生的新封包(JSON 陣列)


  normalizePacket()        ← 將 snake_case 欄位轉為 camelCase
  (srcDevice, dstDevice, protocol, summary, layers...)


  packets.value = [...]    ← 更新 Vue reactive ref(上限 500 筆)


  provide(SIM_PACKETS_KEY) ← 透過 Vue provide/inject 傳遞給子元件

    ┌────┼────┐
    ▼    ▼    ▼
 Topology  TrafficLog  Terminal
 (Canvas)  (Vue DOM)   (xterm.js)

初始化流程

  1. 使用者進入挑戰頁面,ChallengeLayout.vue 被掛載
  2. SimNet.vueonMounted 觸發 loadConfig(path)
  3. useChallenge.ts 透過 fetch() 取得 config.yaml(已由 VitePress 建置流程轉為 JSON)
  4. 將 config JSON 傳入 useSimulation.init(configJson)
  5. init() 動態載入 WASM 模組(import('/wasm/simnet_wasm.js')),呼叫 __wbg_init() 初始化
  6. 以 config JSON 建構 SimNetEngine 實例
  7. requestAnimationFrame 迴圈啟動,模擬開始運行

封包正規化

WASM 引擎回傳的封包使用 Rust 風格的 snake_case 命名,normalizePacket() 函式負責轉換為前端慣用的 camelCase

WASM 欄位正規化後
src_devicesrcDevice
dst_devicedstDevice
protocolprotocol(不變)
summarysummary(不變)
layerslayers(不變)

每個封包會被賦予遞增的唯一 id,用於 Vue 的 v-for :key 追蹤。

5. 主題系統

SimNet 使用 CSS custom properties 實作深色/淺色主題切換,與 VitePress 的 .dark class 機制整合。

色彩架構

所有色彩定義於 .vitepress/theme/style.css,分為以下類別:

類別變數前綴範例
基底色--color-sim-bg, --color-sim-panel背景、面板、邊框
強調色--color-sim-accent深色模式:Cyber Green #00ffaa;淺色模式:Indigo #4f46e5
語意色--color-sim-info, --color-sim-warn, --color-sim-danger狀態指示
文字色--color-sim-text, --color-sim-text-muted, --color-sim-text-dim主要、次要、暗淡文字
協定色--color-proto-ethernet, --color-proto-arp, ...封包依協定類型上色

深色/淺色切換

css
/* 深色模式(預設) */
@theme {
  --color-sim-bg: #101828;
  --color-sim-accent: #00ffaa;
  /* ... */
}

/* 淺色模式覆寫 */
:root:not(.dark) {
  --color-sim-bg: #f1f5f9;
  --color-sim-accent: #4f46e5;
  /* ... */
}

VitePress 在 <html> 元素上切換 .dark class,所有 SimNet 元件自動跟隨切換。

終端機始終深色

即使在淺色模式下,終端機面板也維持深色主題(符合真實終端機的視覺慣例):

css
:root:not(.dark) .sim-terminal {
  --color-sim-panel: #1e293b;
  --color-sim-bg: #0f172a;
  /* ... */
}

6. 挑戰框架

挑戰系統的資料流從 YAML 設定檔開始,經過多個階段最終呈現為互動式模擬。

挑戰載入流程

config.yaml                 frontmatter (index.md)
    │                              │
    ▼                              ▼
VitePress build              Layout.vue
(YAML → JSON)               偵測 layout: "challenge"
    │                              │
    ▼                              ▼
fetch(config.json)           ChallengeLayout.vue
    │                              │
    ▼                              ▼
useChallenge.ts              SimNet.vue
(狀態機管理)                  (provide engine + packets)
    │                              │
    ▼                              ▼
useSimulation.init()         子元件渲染
(WASM 引擎初始化)             Topology / TrafficLog / Terminal

挑戰狀態機

useChallenge.ts 管理四種狀態:

loading ──→ running ──→ completed
   │                       ▲
   └──→ error              │
                    submitFlag(正確)
  • loading:正在載入 config 並初始化 WASM 引擎
  • running:模擬運行中,使用者可以觀察封包、下達指令
  • completed:Flag 驗證成功
  • error:config 載入失敗或 WASM 初始化錯誤

Flag 驗證機制

Flag 驗證在瀏覽器端使用 Web Crypto API 計算 SHA-256 hash(雜湊值),與 config 中預存的 hash 進行比對。明文 Flag 永遠不會出現在前端程式碼中。

使用者輸入 → SHA-256(input) → 與 config.flag.hash 比對 → correct / incorrect

響應式版面

SimNet.vue 透過 useBreakpoint.ts 偵測螢幕寬度,提供三種版面:

斷點版面特色
Desktop(桌面)三面板 + 側邊功能列ResizablePanel 可拖曳調整大小
Tablet(平板)上方標籤切換 + 下方終端機Topology / Traffic 標籤切換
Mobile(手機)底部導覽列 + 單一全螢幕面板五個標籤:Topo / Traffic / Term / Mission / Hints

7. Semantic Engine(語意引擎)

Semantic Engine 負責解析挑戰設定(config.yaml),建構語意模型(Semantic Model)。它不只是讀取拓撲資料,而是理解網路的語意——路由關係、DNS 解析鏈、服務可達性。

職責

  • 拓撲建模:將 topology.nodestopology.links 轉換為圖結構,計算可達性
  • 路由語意:根據裝置的 IP/子網路設定,建構路由表與轉發邏輯
  • DNS 語意:解析 DNS 服務設定,建構域名→IP 對應表
  • 服務語意:標記哪些裝置提供哪些服務(HTTP、DNS),用於行為引擎的事件派發

故障與攻擊模型

DSL v2 的 faultsattacks 區塊由 Semantic Engine 解析為語意操作:

  • 故障(Faults):路由缺失、DNS 紀錄錯誤、介面停用——這些是初始狀態的「損壞」
  • 攻擊(Attacks):ARP spoofing、MITM、DoS——這些是環境中持續進行的惡意行為

8. Behavior Engine(行為引擎)

Behavior Engine 負責驅動模擬的動態行為,包括事件規則執行、故障/攻擊展開、以及勝利條件評估。

事件規則

事件規則定義在 config.yamlevents 區塊中,Behavior Engine 在每個 tick 中評估:

  1. 時間觸發periodic_frameperiodic_communication 等依照 interval_ms 週期觸發
  2. 條件觸發trigger 欄位指定的條件成立時觸發(如 mitm_active
  3. 鏈式觸發:一個事件的結果可觸發另一個事件

故障/攻擊展開

Semantic Engine 提供的故障與攻擊模型,由 Behavior Engine 在模擬啟動時展開為具體的事件序列:

  • 路由缺失 → 刪除路由表中的特定條目
  • ARP spoofing → 週期性注入偽造的 ARP reply
  • DoS flood → 產生大量 SYN 封包

勝利條件評估

win_condition 定義了挑戰完成的判定邏輯,Behavior Engine 在每個 tick 後檢查:

類型說明
capture_payload玩家擷取到包含特定內容的封包
connectivity_restored指定裝置間的連線恢復
defense_active玩家成功啟用所有要求的防禦措施
service_available指定服務恢復可用狀態

9. DSL v2 架構

DSL v2 是 SimNet 的挑戰設定語言,以 config.yaml 為載體,描述完整的挑戰情境。

資料流

mermaid
graph TB
    YAML[config.yaml] --> Parser[DSL v2 Parser]
    Parser --> SM[Semantic Model]
    SM --> BE[Behavior Engine]
    BE --> Sim[Simulation Loop]
    Sim --> UI[Vue Components]
    UI --> TL[TrafficLog]
    UI --> TV[TopologyView]
    UI --> Term[Terminal]

config.yaml 結構總覽

yaml
challenge:          # 挑戰中繼資料
  id, title, difficulty, category, flag

topology:           # 網路拓撲
  nodes: [...]      # 裝置定義
  links: [...]      # 連線定義

faults:             # 故障定義(Network Repair 類別使用)
  - type: missing_route
    device: router1
    destination: 10.0.2.0/24

attacks:            # 攻擊定義(Security Attack / Transmission Defense 類別使用)
  - type: arp_spoofing
    attacker: eve
    target: pc1
    impersonates: gateway

player_tools:       # 玩家可用工具
  - tcpdump         # 封包擷取
  - arp             # ARP 表查看
  - ip              # 路由與介面操作
  - ping            # 連通性測試

hints:              # 分階段提示
  - trigger: after_30s
    text: "..."

win_condition:      # 勝利條件
  type: capture_payload | connectivity_restored | defense_active

從 config.yaml 到模擬器

  1. VitePress 建置:YAML 被轉換為 JSON,Flag 佔位符被替換
  2. DSL v2 Parser:驗證結構、展開語法糖、解析引用關係
  3. Semantic Model:建構網路語意模型(路由表、DNS 表、服務表)
  4. Behavior Engine:將 faults/attacks/events 展開為事件佇列
  5. Simulation Loop:每個 tick 推進模擬、評估勝利條件
  6. Vue Components:響應式渲染拓撲圖、封包日誌、終端機

接下來,閱讀如何擴充模板來了解如何為 SimNet 建立新的內容。