Scert/backend/internal/firewall/windows.go

69 lines
2.9 KiB
Go
Raw Permalink 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.

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
}