mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-10-12 01:58:46 +02:00
cli: add network fallback and explicit-only Internal Domain modes
Internal Domains now support three modes. "os" is unchanged. "resolvers" becomes explicit resolver with network fallback: the configured resolvers are tried first, and a timeout, unreachable resolver, SERVFAIL or NXDOMAIN hands the query to matching VPN DNS servers, then domain-less VPN DNS servers, then the OS resolver's LAN nameservers through the new LanOnlyQueryCtx. "resolvers_only" keeps the previous strict behavior. Down fallback-mode resolvers are skipped and re-checked in the background at most every 30s. Generated upstreams are identified by the UpstreamConfig.InternalDomain marker instead of the internal_ key prefix. Master adaptations: the fallback state lives on proxyRequest and is applied in tryUpstreams, shouldContinueWithNextUpstream and handleAllUpstreamsFailure instead of v1.0's monolithic proxy loop. Resolver construction uses master's context-aware NewResolver, and the background re-check marks its context private so transport errors that name the resolver stay at debug. Tests use master's zap JSON capture and VPN manager logger.
This commit is contained in:
1 parent
bfc46ef265
commit
b0408e4d1c
17 files changed
+1334
-138
No files matched your search
@@ -109,17 +109,30 @@ type ResolverConfig struct {
|
||||
}
|
||||
|
||||
// Internal Domain resolution modes. Mode is what the administrator selected;
|
||||
// Resolvers is only meaningful under SplitDNSModeResolvers.
|
||||
// Resolvers is only meaningful under SplitDNSModeResolvers and
|
||||
// SplitDNSModeResolversOnly.
|
||||
const (
|
||||
// SplitDNSModeOS follows the endpoint's own OS/default resolver.
|
||||
SplitDNSModeOS = "os"
|
||||
// SplitDNSModeResolvers uses the configured addresses and nothing else.
|
||||
// SplitDNSModeResolvers resolves the domain through the addresses in
|
||||
// Resolvers first. When none of them answers, or they answer SERVFAIL or
|
||||
// NXDOMAIN, the query falls back to the resolvers of the endpoint's active
|
||||
// network and VPN. This is the default explicit selection.
|
||||
SplitDNSModeResolvers = "resolvers"
|
||||
// SplitDNSModeResolversOnly resolves the domain through the addresses in
|
||||
// Resolvers and nothing else: their answer, or their failure, is final.
|
||||
SplitDNSModeResolversOnly = "resolvers_only"
|
||||
)
|
||||
|
||||
// SplitDNS is one organization Internal Domain. Mode decides the routing;
|
||||
// Resolvers is read only under SplitDNSModeResolvers. An empty Mode predates
|
||||
// the field, so the caller infers the mode from Resolvers in that case.
|
||||
// SplitDNS is one organization Internal Domain: a domain suffix, the resolution
|
||||
// mode the organization administrator selected for it, and the resolver
|
||||
// addresses that mode may need.
|
||||
//
|
||||
// Mode decides the routing. Resolvers is read only under the explicit modes,
|
||||
// so addresses left behind by an earlier selection cannot resurrect themselves
|
||||
// once the administrator switches back to the OS resolver. An empty Mode is a
|
||||
// deployment that predates the field; the caller infers the mode from
|
||||
// Resolvers in that case.
|
||||
type SplitDNS struct {
|
||||
Domain string `json:"domain"`
|
||||
Mode string `json:"mode"`
|
||||
|
||||
@@ -112,6 +112,11 @@ func TestResolverConfigParsesSplitDNSMode(t *testing.T) {
|
||||
"domain": "office.example.com",
|
||||
"mode": "os",
|
||||
"resolvers": []
|
||||
},
|
||||
{
|
||||
"domain": "vault.example.com",
|
||||
"mode": "resolvers_only",
|
||||
"resolvers": ["10.0.0.55"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -122,7 +127,7 @@ func TestResolverConfigParsesSplitDNSMode(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := resp.Body.Resolver.SplitDNS
|
||||
if len(got) != 2 {
|
||||
if len(got) != 3 {
|
||||
t.Fatalf("split_dns = %+v", got)
|
||||
}
|
||||
if got[0].Domain != "corp.example.com" || got[0].Mode != SplitDNSModeResolvers {
|
||||
@@ -137,6 +142,9 @@ func TestResolverConfigParsesSplitDNSMode(t *testing.T) {
|
||||
if len(got[1].Resolvers) != 0 {
|
||||
t.Errorf("[1].Resolvers = %v, want empty", got[1].Resolvers)
|
||||
}
|
||||
if got[2].Mode != SplitDNSModeResolversOnly || len(got[2].Resolvers) != 1 {
|
||||
t.Errorf("[2] = %+v", got[2])
|
||||
}
|
||||
}
|
||||
|
||||
// A response without the field must still decode, so a deployment that predates
|
||||
|
||||
Reference in new issue
Block a user