mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-07-04 01:07:49 +02:00
all: add UpstreamConfig.VerifyDomain
So the self-check process is only done for ControlD upstream, and can be distinguished between .com and .dev resolvers.
This commit is contained in:
committed by
Cuong Manh Le
parent
54e63ccf9b
commit
8fda856e24
+14
-7
@@ -36,8 +36,6 @@ import (
|
|||||||
"github.com/Control-D-Inc/ctrld/internal/router"
|
"github.com/Control-D-Inc/ctrld/internal/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
const selfCheckFQDN = "verify.controld.com"
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
version = "dev"
|
version = "dev"
|
||||||
commit = "none"
|
commit = "none"
|
||||||
@@ -289,6 +287,10 @@ func initCLI() {
|
|||||||
|
|
||||||
processCDFlags()
|
processCDFlags()
|
||||||
|
|
||||||
|
if err := ctrld.ValidateConfig(validator.New(), &cfg); err != nil {
|
||||||
|
mainLog.Fatal().Msgf("invalid config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Explicitly passing config, so on system where home directory could not be obtained,
|
// Explicitly passing config, so on system where home directory could not be obtained,
|
||||||
// or sub-process env is different with the parent, we still behave correctly and use
|
// or sub-process env is different with the parent, we still behave correctly and use
|
||||||
// the expected config file.
|
// the expected config file.
|
||||||
@@ -320,7 +322,8 @@ func initCLI() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
status = selfCheckStatus(status)
|
domain := cfg.Upstream["0"].VerifyDomain()
|
||||||
|
status = selfCheckStatus(status, domain)
|
||||||
switch status {
|
switch status {
|
||||||
case service.StatusRunning:
|
case service.StatusRunning:
|
||||||
mainLog.Notice().Msg("Service started")
|
mainLog.Notice().Msg("Service started")
|
||||||
@@ -855,7 +858,11 @@ func defaultIfaceName() string {
|
|||||||
return dri
|
return dri
|
||||||
}
|
}
|
||||||
|
|
||||||
func selfCheckStatus(status service.Status) service.Status {
|
func selfCheckStatus(status service.Status, domain string) service.Status {
|
||||||
|
if domain == "" {
|
||||||
|
// Nothing to do, return the status as-is.
|
||||||
|
return status
|
||||||
|
}
|
||||||
c := new(dns.Client)
|
c := new(dns.Client)
|
||||||
bo := backoff.NewBackoff("self-check", logf, 10*time.Second)
|
bo := backoff.NewBackoff("self-check", logf, 10*time.Second)
|
||||||
bo.LogLongerThan = 500 * time.Millisecond
|
bo.LogLongerThan = 500 * time.Millisecond
|
||||||
@@ -883,16 +890,16 @@ func selfCheckStatus(status service.Status) service.Status {
|
|||||||
}
|
}
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.SetQuestion(selfCheckFQDN+".", dns.TypeA)
|
m.SetQuestion(domain+".", dns.TypeA)
|
||||||
m.RecursionDesired = true
|
m.RecursionDesired = true
|
||||||
r, _, err := c.ExchangeContext(ctx, m, net.JoinHostPort(lc.IP, strconv.Itoa(lc.Port)))
|
r, _, err := c.ExchangeContext(ctx, m, net.JoinHostPort(lc.IP, strconv.Itoa(lc.Port)))
|
||||||
if r != nil && r.Rcode == dns.RcodeSuccess && len(r.Answer) > 0 {
|
if r != nil && r.Rcode == dns.RcodeSuccess && len(r.Answer) > 0 {
|
||||||
mainLog.Debug().Msgf("self-check against %q succeeded", selfCheckFQDN)
|
mainLog.Debug().Msgf("self-check against %q succeeded", domain)
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
bo.BackOff(ctx, fmt.Errorf("ExchangeContext: %w", err))
|
bo.BackOff(ctx, fmt.Errorf("ExchangeContext: %w", err))
|
||||||
}
|
}
|
||||||
mainLog.Debug().Msgf("self-check against %q failed", selfCheckFQDN)
|
mainLog.Debug().Msgf("self-check against %q failed", domain)
|
||||||
return service.StatusUnknown
|
return service.StatusUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ func Test_macFromMsg(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.SetQuestion(selfCheckFQDN+".", dns.TypeA)
|
m.SetQuestion("example.com.", dns.TypeA)
|
||||||
o := &dns.OPT{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeOPT}}
|
o := &dns.OPT{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeOPT}}
|
||||||
if tc.wantMac {
|
if tc.wantMac {
|
||||||
ec1 := &dns.EDNS0_LOCAL{Code: EDNS0_OPTION_MAC, Data: hw}
|
ec1 := &dns.EDNS0_LOCAL{Code: EDNS0_OPTION_MAC, Data: hw}
|
||||||
|
|||||||
@@ -29,9 +29,19 @@ const (
|
|||||||
IpStackV4 = "v4"
|
IpStackV4 = "v4"
|
||||||
IpStackV6 = "v6"
|
IpStackV6 = "v6"
|
||||||
IpStackSplit = "split"
|
IpStackSplit = "split"
|
||||||
|
|
||||||
|
controlDComDomain = "controld.com"
|
||||||
|
controlDNetDomain = "controld.net"
|
||||||
|
controlDDevDomain = "controld.dev"
|
||||||
)
|
)
|
||||||
|
|
||||||
var controldParentDomains = []string{"controld.com", "controld.net", "controld.dev"}
|
var (
|
||||||
|
controldParentDomains = []string{controlDComDomain, controlDNetDomain, controlDDevDomain}
|
||||||
|
controldVerifiedDomain = map[string]string{
|
||||||
|
controlDComDomain: "verify.controld.com",
|
||||||
|
controlDDevDomain: "verify.controld.dev",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// SetConfigName set the config name that ctrld will look for.
|
// SetConfigName set the config name that ctrld will look for.
|
||||||
// DEPRECATED: use SetConfigNameWithPath instead.
|
// DEPRECATED: use SetConfigNameWithPath instead.
|
||||||
@@ -201,6 +211,23 @@ func (uc *UpstreamConfig) Init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyDomain returns the domain name that could be resolved by the upstream endpoint.
|
||||||
|
// It returns empty for non-ControlD upstream endpoint.
|
||||||
|
func (uc *UpstreamConfig) VerifyDomain() string {
|
||||||
|
domain := uc.Domain
|
||||||
|
if domain == "" {
|
||||||
|
if u, err := url.Parse(uc.Endpoint); err == nil {
|
||||||
|
domain = u.Hostname()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, parent := range controldParentDomains {
|
||||||
|
if dns.IsSubDomain(parent, domain) {
|
||||||
|
return controldVerifiedDomain[parent]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// UpstreamSendClientInfo reports whether the upstream is
|
// UpstreamSendClientInfo reports whether the upstream is
|
||||||
// configured to send client info to Control D DNS server.
|
// configured to send client info to Control D DNS server.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -190,6 +190,39 @@ func TestUpstreamConfig_Init(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpstreamConfig_VerifyDomain(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
uc *UpstreamConfig
|
||||||
|
verifyDomain string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
controlDComDomain,
|
||||||
|
&UpstreamConfig{Endpoint: "https://freedns.controld.com/p2"},
|
||||||
|
controldVerifiedDomain[controlDComDomain],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
controlDDevDomain,
|
||||||
|
&UpstreamConfig{Endpoint: "https://freedns.controld.dev/p2"},
|
||||||
|
controldVerifiedDomain[controlDDevDomain],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"non-ControlD upstream",
|
||||||
|
&UpstreamConfig{Endpoint: "https://dns.google/dns-query"},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
if got := tc.uc.VerifyDomain(); got != tc.verifyDomain {
|
||||||
|
t.Errorf("unexpected verify domain, want: %q, got: %q", tc.verifyDomain, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
func ptrBool(b bool) *bool {
|
func ptrBool(b bool) *bool {
|
||||||
return &b
|
return &b
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user