Files
nodeagent/scripts/rescue-network.ps1
T
jkooe 2cb0ed148e chore(privacy): 源码与测试里的真机常量脱敏(机器名 / 真机内网 IP)
路线图 §七 序 7「源码真机常量注入化」的脱敏部分。

## 改了什么
- apps/agent/src/capabilities/network.ts:注释里的真机机器名 → 泛化为「机器名+纯数字」
  (保留"为什么不能拼 USERDOMAIN/USERNAME"这个教训本身,去掉具体机器名)
- scripts/rescue-network.ps1:.EXAMPLE 里的真机内网地址 → 文档示例段 192.168.1.100;
  网卡名示例由中文默认名改为 'Ethernet'(既避免像真机、又更通用)
- packages/protocol/src/acl.ts:注释里的真机 Mac 地址 → 192.168.1.100
- tests/unit×4:测试数据里的真机 IP 统一换成 192.168.1.x 示例段

## 过程中的两个教训(都记在代码注释里了)
1. **正则转义形态漏替换**:断言里写的是 `192\.168\.0\.88`(转义点),第一轮只替换了
   裸形态 `192.168.0.`,导致脚本值变了、断言没变 → 3 个测试红。
2. **机械替换会破坏「跨网段」这类语义测试**:acl 的 `/24 网段匹配` 用例里有一条
   本意是「**不同网段不匹配**」,替换后两侧变成同段 → 断言必红。已改回不同网段
   并在注释里标注原因,防止下次再被批量替换破坏。

## 验证
单测 269 全绿(复跑);e2e 30 全绿。
2026-10-10 00:39:28 +08:00

150 lines
7.2 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<#
.SYNOPSIS
nodeagent 网络救援脚本 —— 被控端因网络变更失联后的本地恢复。
.DESCRIPTION
背景:`system.net.apply` 是两阶段提交(未确认自动回滚),但**如果回滚本身也失败**
(例如变更脚本把地址删掉了却没加上),机器可能落到 APIPA(169.254.x.x)而彻底失联。
这个脚本就是为那一天准备的:在**被控端本机**以管理员运行,把网络恢复到可用状态。
它做的事:
1. 列出所有网卡与当前地址(先看清现状)
2. 找出「有物理连接、但没有有效 IPv4」的网卡(典型的失联状态)
3. 把指定/自动识别的网卡设回给定静态地址,或切回 DHCP
4. 用**原生 NetTCPIP cmdlet** 按安全顺序执行:
先加地址 → 再清其它地址与残留默认路由 → 最后补默认路由
(顺序颠倒会踩 Windows 的「already exists」而再次失败 —— 真机事故根因)
.PARAMETER Interface
网卡别名(如「Ethernet」)。省略则自动选取「已连接但无有效 IPv4」的那块。
.PARAMETER Ip / PrefixLength / Gateway / Dns
要恢复的静态配置;省略 Ip 则切回 DHCP。
.PARAMETER ListOnly
只看现状,不做任何变更。
.EXAMPLE
# 先看现状
powershell -ExecutionPolicy Bypass -File rescue-network.ps1 -ListOnly
.EXAMPLE
# 恢复为原静态地址(最常用)
powershell -ExecutionPolicy Bypass -File rescue-network.ps1 `
-Interface 'Ethernet' -Ip 192.168.1.100 -PrefixLength 24 -Gateway 192.168.1.1
.EXAMPLE
# 切回 DHCP(家里路由器会重新分配地址)
powershell -ExecutionPolicy Bypass -File rescue-network.ps1 -Interface 'Ethernet'
#>
[CmdletBinding()]
param(
[string]$Interface,
[string]$Ip,
[int]$PrefixLength = 24,
[string]$Gateway,
[string[]]$Dns,
[switch]$ListOnly
)
$ErrorActionPreference = 'Continue'
function Write-Step($m) { Write-Host "[*] $m" -ForegroundColor Cyan }
function Write-Ok($m) { Write-Host "[+] $m" -ForegroundColor Green }
function Write-Warn2($m) { Write-Host "[!] $m" -ForegroundColor Yellow }
function Write-Err2($m) { Write-Host "[x] $m" -ForegroundColor Red }
Write-Host ""
Write-Host " nodeagent 网络救援" -ForegroundColor White
Write-Host " ------------------" -ForegroundColor DarkGray
# ---------- 1. 现状 ----------
Write-Step "当前网卡与地址:"
$adapters = Get-NetAdapter | Sort-Object ifIndex
foreach ($a in $adapters) {
$addrs = @(Get-NetIPAddress -InterfaceIndex $a.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue |
Where-Object { $_.PrefixOrigin -ne 'WellKnown' } | ForEach-Object { "$($_.IPAddress)/$($_.PrefixLength)" })
$dhcp = (Get-NetIPInterface -InterfaceIndex $a.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue).Dhcp
$mark = if ($a.Status -eq 'Up' -and $addrs.Count -eq 0) { ' <== 已连接但无地址(疑似失联)' } else { '' }
Write-Host (" {0,-22} {1,-8} dhcp={2,-8} {3}{4}" -f $a.Name, $a.Status, $dhcp, ($addrs -join ', '), $mark)
}
$gw = @(Get-NetRoute -AddressFamily IPv4 -DestinationPrefix '0.0.0.0/0' -ErrorAction SilentlyContinue |
ForEach-Object { "$($_.NextHop) (ifIndex $($_.ifIndex))" })
# 注意:PowerShell 5.1 的 if 不能当表达式内联在括号里 —— 必须先算好再拼(写错会直接语法错误)
$gwText = if ($gw.Count -gt 0) { $gw -join ', ' } else { '(无 —— 这就是回包发不出去的原因)' }
Write-Step ("默认路由: " + $gwText)
if ($ListOnly) { Write-Host ""; Write-Ok "仅查看模式,未做任何变更"; exit 0 }
# ---------- 2. 选目标网卡 ----------
if (-not $Interface) {
$cand = $adapters | Where-Object {
$_.Status -eq 'Up' -and
@(Get-NetIPAddress -InterfaceIndex $_.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue |
Where-Object { $_.PrefixOrigin -ne 'WellKnown' }).Count -eq 0
} | Select-Object -First 1
if (-not $cand) {
$cand = $adapters | Where-Object { $_.Status -eq 'Up' } | Select-Object -First 1
}
if (-not $cand) { Write-Err2 "找不到可用的已连接网卡,请用 -Interface 指定"; exit 1 }
$Interface = $cand.Name
Write-Warn2 "未指定网卡,自动选用:$Interface"
}
if (-not (Get-NetAdapter -Name $Interface -ErrorAction SilentlyContinue)) {
Write-Err2 "网卡不存在:$Interface"; exit 1
}
# ---------- 3. 执行 ----------
if (-not $Ip) {
Write-Step "切回 DHCP:$Interface"
Set-NetIPInterface -InterfaceAlias $Interface -Dhcp Enabled -ErrorAction SilentlyContinue
Set-DnsClientServerAddress -InterfaceAlias $Interface -ResetServerAddresses -ErrorAction SilentlyContinue
Write-Ok "已切回 DHCP(稍等几秒应拿到地址)"
} else {
Write-Step "恢复静态地址 $Ip/$PrefixLength (网卡 $Interface)"
Set-NetIPInterface -InterfaceAlias $Interface -Dhcp Disabled -ErrorAction SilentlyContinue
# ⚠️ 顺序不可颠倒:先加新地址(过渡期链路不断),再清旧地址/残留路由,最后补路由。
# 颠倒会触发 Windows 的「实例已存在」→ 地址加不上 → 再次失联(真机事故根因)。
New-NetIPAddress -InterfaceAlias $Interface -IPAddress $Ip -PrefixLength $PrefixLength -ErrorAction SilentlyContinue | Out-Null
Get-NetRoute -InterfaceAlias $Interface -DestinationPrefix '0.0.0.0/0' -ErrorAction SilentlyContinue |
Remove-NetRoute -Confirm:$false -ErrorAction SilentlyContinue
Get-NetIPAddress -InterfaceAlias $Interface -AddressFamily IPv4 -ErrorAction SilentlyContinue |
Where-Object { $_.IPAddress -ne $Ip -and $_.PrefixOrigin -ne 'WellKnown' } |
ForEach-Object { Remove-NetIPAddress -IPAddress $_.IPAddress -InterfaceAlias $Interface -Confirm:$false -ErrorAction SilentlyContinue }
if ($Gateway) {
New-NetRoute -InterfaceAlias $Interface -DestinationPrefix '0.0.0.0/0' -NextHop $Gateway -ErrorAction SilentlyContinue | Out-Null
}
if ($Dns -and $Dns.Count -gt 0) {
Set-DnsClientServerAddress -InterfaceAlias $Interface -ServerAddresses $Dns -ErrorAction SilentlyContinue
}
}
Start-Sleep -Seconds 3
# ---------- 4. 自检 ----------
Write-Step "自检:"
$now = @(Get-NetIPAddress -InterfaceAlias $Interface -AddressFamily IPv4 -ErrorAction SilentlyContinue |
Where-Object { $_.PrefixOrigin -ne 'WellKnown' } | ForEach-Object { "$($_.IPAddress)/$($_.PrefixLength)" })
$nowGw = @(Get-NetRoute -InterfaceAlias $Interface -AddressFamily IPv4 -DestinationPrefix '0.0.0.0/0' -ErrorAction SilentlyContinue |
ForEach-Object { $_.NextHop })
if ($now.Count -gt 0) {
Write-Ok ("地址: " + ($now -join ', '))
if ($Ip -and $nowGw.Count -eq 0) {
Write-Warn2 "没有默认路由 —— 只能同网段互访;请补 -Gateway"
} elseif ($nowGw.Count -gt 0) {
Write-Ok ("默认路由: " + ($nowGw -join ', '))
}
Write-Host ""
Write-Ok "网络已恢复。可在 Mac 上执行: nodeagent connect $($now[0].Split('/')[0]) --port 8765 --key <PSK> --insecure"
} else {
Write-Err2 "仍然没有有效地址 —— 请检查网线/交换机,或尝试: rescue-network.ps1 -Interface '$Interface'(不带 -Ip,切回 DHCP)"
exit 1
}