2befe64a0c
Firewall:
- On service initialize/install, create an idempotent inbound allow rule
("OrchestrAD") for the configured listen port, scoped to RFC 1918 private
ranges plus CGNAT (10/8, 172.16/12, 192.168/16, 100.64/10). The rule is
deleted-then-added so it always reflects the current port, and removed on
service uninstall. Best-effort (needs admin; the MSI custom action and
service run elevated); no-op off Windows. Verified the netsh rule lands
with the expected port and remote-address scoping.
MSI:
- Skip the license/EULA page (Welcome now goes straight to the install
directory), since it was blank. A standard short notice is kept in
license.rtf only so the stock license control resolves at build time.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
52 lines
1.7 KiB
Go
52 lines
1.7 KiB
Go
//go:build windows
|
|
|
|
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"strconv"
|
|
|
|
"github.com/Grace-Solutions/OrchestrAD/internal/logging"
|
|
)
|
|
|
|
const firewallRuleName = "OrchestrAD"
|
|
|
|
// firewallRemoteIP scopes the inbound rule to RFC 1918 private ranges plus the
|
|
// carrier-grade NAT range (100.64.0.0/10). Loopback is exempt from the firewall
|
|
// so localhost is unaffected.
|
|
const firewallRemoteIP = "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,100.64.0.0/10"
|
|
|
|
// EnsureFirewallRule idempotently creates the inbound allow rule for the service
|
|
// port. It first deletes any rule of the same name so the rule always reflects
|
|
// the current port, then adds it. Requires administrative rights (the MSI custom
|
|
// action and the service run elevated).
|
|
func EnsureFirewallRule(port int) error {
|
|
// Best-effort delete of a prior rule (ignore "no rules match").
|
|
_ = exec.Command("netsh", "advfirewall", "firewall", "delete", "rule",
|
|
"name="+firewallRuleName).Run()
|
|
|
|
out, err := exec.Command("netsh", "advfirewall", "firewall", "add", "rule",
|
|
"name="+firewallRuleName,
|
|
"dir=in", "action=allow", "protocol=TCP",
|
|
"localport="+strconv.Itoa(port),
|
|
"remoteip="+firewallRemoteIP,
|
|
"profile=any",
|
|
"description=OrchestrAD inbound (RFC1918 + CGNAT)",
|
|
).CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("netsh add rule failed: %v: %s", err, out)
|
|
}
|
|
logging.Info("Firewall", "Inbound rule '%s' allows TCP %d from %s", firewallRuleName, port, firewallRemoteIP)
|
|
return nil
|
|
}
|
|
|
|
// RemoveFirewallRule idempotently deletes the inbound rule. A missing rule is
|
|
// not an error.
|
|
func RemoveFirewallRule() error {
|
|
_ = exec.Command("netsh", "advfirewall", "firewall", "delete", "rule",
|
|
"name="+firewallRuleName).Run()
|
|
logging.Info("Firewall", "Inbound rule '%s' removed", firewallRuleName)
|
|
return nil
|
|
}
|