69 lines
2.9 KiB
Go
69 lines
2.9 KiB
Go
package firewall
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strconv"
|
||
"strings"
|
||
)
|
||
|
||
const (
|
||
windowsStatusScript = `$ErrorActionPreference='Stop'; if ((Get-NetFirewallProfile | Where-Object { $_.Enabled }).Count -gt 0) { Write-Output 'enabled' } else { Write-Output 'disabled' }`
|
||
windowsQueryScript = `$ErrorActionPreference='Stop'; $rule=Get-NetFirewallRule -DisplayName $args[0] -ErrorAction SilentlyContinue; if ($null -eq $rule) { exit 3 }; exit 0`
|
||
windowsAddScript = `$ErrorActionPreference='Stop'; New-NetFirewallRule -DisplayName $args[0] -Direction Inbound -Action Allow -Enabled True -Profile Any -Protocol TCP -LocalPort ([int]$args[1]) | Out-Null`
|
||
windowsRemoveScript = `$ErrorActionPreference='Stop'; Remove-NetFirewallRule -DisplayName $args[0]`
|
||
)
|
||
|
||
func (m *manager) openWindows(ctx context.Context, port int) (Result, error) {
|
||
powershell, err := m.runner.LookPath("powershell.exe")
|
||
if err != nil {
|
||
return Result{}, fmt.Errorf("未找到 Windows PowerShell,无法配置本机防火墙:%w", err)
|
||
}
|
||
status, err := m.runner.Run(ctx, powershell, "-NoProfile", "-NonInteractive", "-Command", windowsStatusScript)
|
||
if err != nil || status.ExitCode != 0 {
|
||
return Result{}, commandError("检查 Windows 防火墙状态", powershell, status, err)
|
||
}
|
||
if !strings.Contains(strings.ToLower(string(status.Output)), "enabled") {
|
||
return Result{
|
||
Backend: BackendNone, Port: port,
|
||
Message: "Windows 防火墙当前未启用,无需创建主服务端口入站规则",
|
||
}, nil
|
||
}
|
||
|
||
name := ruleName(port)
|
||
query, err := m.runner.Run(ctx, powershell, "-NoProfile", "-NonInteractive", "-Command", windowsQueryScript, name)
|
||
if err != nil {
|
||
return Result{}, commandError("检查 Windows 防火墙规则", powershell, query, err)
|
||
}
|
||
if query.ExitCode == 0 {
|
||
return Result{
|
||
Backend: backendWindows, RuleName: name, Port: port,
|
||
Message: fmt.Sprintf("Windows 防火墙规则已存在:%s", name),
|
||
}, nil
|
||
}
|
||
if query.ExitCode != 3 {
|
||
return Result{}, commandError("检查 Windows 防火墙规则", powershell, query, nil)
|
||
}
|
||
|
||
added, err := m.runner.Run(ctx, powershell, "-NoProfile", "-NonInteractive", "-Command", windowsAddScript, name, strconv.Itoa(port))
|
||
if err != nil || added.ExitCode != 0 {
|
||
return Result{}, commandError("创建 Windows 防火墙入站规则", powershell, added, err)
|
||
}
|
||
return Result{
|
||
Backend: backendWindows, RuleName: name, Port: port, Created: true,
|
||
Message: fmt.Sprintf("已创建 Windows 防火墙规则:%s", name),
|
||
}, nil
|
||
}
|
||
|
||
func (m *manager) rollbackWindows(ctx context.Context, result Result) error {
|
||
powershell, err := m.runner.LookPath("powershell.exe")
|
||
if err != nil {
|
||
return fmt.Errorf("未找到 Windows PowerShell,无法回滚防火墙规则:%w", err)
|
||
}
|
||
removed, err := m.runner.Run(ctx, powershell, "-NoProfile", "-NonInteractive", "-Command", windowsRemoveScript, result.RuleName)
|
||
if err != nil || removed.ExitCode != 0 {
|
||
return commandError("回滚 Windows 防火墙规则", powershell, removed, err)
|
||
}
|
||
return nil
|
||
}
|