Files
ctrld/cmd/cli/nrpt_external_gp.go
T

64 lines
2.8 KiB
Go

package cli
import (
"errors"
"net/netip"
"strings"
)
const nrptRuleName = `CtrldCatchAll`
// errGPNRPTVerified marks an intercept startup failure that happened while an externally
// managed (Group Policy) NRPT catch-all was proved - by probe, not by registry shape
// alone - to be routing DNS to this listener. It is the difference between "intercept
// failed but DNS still reaches ctrld" and "intercept failed and nothing is filtering",
// which is what decides whether the interface-DNS fallback must run.
//
// Only the Windows path produces it, but setDNS is shared, so the sentinel and its
// predicate live here with the other platform-neutral NRPT helpers.
var errGPNRPTVerified = errors.New("GP-managed NRPT verified routing to ctrld")
// errGPNRPTIneffective marks a startup that ends with externally managed NRPT owning the
// namespace while no probe has proved it routes to ctrld. DNS is not reaching ctrld, but
// adapter DNS was deliberately preserved and no ctrld rule may be written beside an
// administrator's catch-all - so this is a failed start that must not take the
// interface-DNS fallback either.
var errGPNRPTIneffective = errors.New("GP-managed NRPT owns the namespace but no probe reached ctrld")
// interceptFailedWithVerifiedExternalDNS reports whether an intercept startup failure
// happened while externally managed DNS policy was verified to be routing to ctrld.
func interceptFailedWithVerifiedExternalDNS(err error) bool {
return errors.Is(err, errGPNRPTVerified)
}
// interceptFailedUnderExternalDNSPolicy reports whether an intercept startup failure
// happened while externally managed DNS policy owned the namespace, whether or not it was
// proved to route. Either way the interface-DNS fallback must not run: adapter DNS was
// preserved on purpose, and rewriting it would violate the policy ctrld just deferred to.
// Only the verified case is a successful start.
func interceptFailedUnderExternalDNSPolicy(err error) bool {
return errors.Is(err, errGPNRPTVerified) || errors.Is(err, errGPNRPTIneffective)
}
// isExternalGPCatchAll recognizes only a single catch-all namespace that is not
// ctrld's deterministic GP key. Registry access stays in the Windows file; this
// pure classifier is shared with host-runnable tests.
func isExternalGPCatchAll(ruleName string, namespaces []string) bool {
return ruleName != "" && !strings.EqualFold(ruleName, nrptRuleName) && len(namespaces) == 1 && strings.TrimSpace(namespaces[0]) == "."
}
func isMatchingGPNRPTRule(ruleName string, namespaces []string, dnsServers, listenerIP string) bool {
if !isExternalGPCatchAll(ruleName, namespaces) {
return false
}
server, err := netip.ParseAddr(strings.TrimSpace(dnsServers))
if err != nil {
return false
}
listener, err := netip.ParseAddr(strings.TrimSpace(listenerIP))
if err != nil {
return false
}
return server.Unmap() == listener.Unmap()
}