mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-02-03 22:18:39 +00:00
fix: ensure upstream health checks can handle large DNS responses
- Add UpstreamConfig.VerifyMsg() method with proper EDNS0 support - Replace hardcoded DNS messages in health checks with standardized verification method - Set EDNS0 buffer size to 4096 bytes to handle large DNS responses - Add test case for legacy resolver with extensive extra sections
This commit is contained in:
committed by
Cuong Manh Le
parent
d71d1341b6
commit
fd48e6d795
@@ -1400,9 +1400,6 @@ func (p *prog) checkUpstreamOnce(upstream string, uc *ctrld.UpstreamConfig) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := new(dns.Msg)
|
|
||||||
msg.SetQuestion(".", dns.TypeNS)
|
|
||||||
|
|
||||||
timeout := 1000 * time.Millisecond
|
timeout := 1000 * time.Millisecond
|
||||||
if uc.Timeout > 0 {
|
if uc.Timeout > 0 {
|
||||||
timeout = time.Millisecond * time.Duration(uc.Timeout)
|
timeout = time.Millisecond * time.Duration(uc.Timeout)
|
||||||
@@ -1416,6 +1413,7 @@ func (p *prog) checkUpstreamOnce(upstream string, uc *ctrld.UpstreamConfig) erro
|
|||||||
mainLog.Load().Debug().Msgf("Rebootstrapping resolver for upstream: %s", upstream)
|
mainLog.Load().Debug().Msgf("Rebootstrapping resolver for upstream: %s", upstream)
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
msg := uc.VerifyMsg()
|
||||||
_, err = resolver.Resolve(ctx, msg)
|
_, err = resolver.Resolve(ctx, msg)
|
||||||
duration := time.Since(start)
|
duration := time.Since(start)
|
||||||
|
|
||||||
|
|||||||
@@ -358,6 +358,15 @@ func (uc *UpstreamConfig) Init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyMsg creates and returns a new DNS message could be used for testing upstream health.
|
||||||
|
func (uc *UpstreamConfig) VerifyMsg() *dns.Msg {
|
||||||
|
msg := new(dns.Msg)
|
||||||
|
msg.RecursionDesired = true
|
||||||
|
msg.SetQuestion(".", dns.TypeNS)
|
||||||
|
msg.SetEdns0(4096, false) // ensure handling of large DNS response
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
// VerifyDomain returns the domain name that could be resolved by the upstream endpoint.
|
// VerifyDomain returns the domain name that could be resolved by the upstream endpoint.
|
||||||
// It returns empty for non-ControlD upstream endpoint.
|
// It returns empty for non-ControlD upstream endpoint.
|
||||||
func (uc *UpstreamConfig) VerifyDomain() string {
|
func (uc *UpstreamConfig) VerifyDomain() string {
|
||||||
|
|||||||
@@ -120,8 +120,7 @@ func (p *ptrDiscover) lookupIPByHostname(name string, v6 bool) string {
|
|||||||
// is reachable, set p.serverDown to false, so p.lookupHostname can continue working.
|
// is reachable, set p.serverDown to false, so p.lookupHostname can continue working.
|
||||||
func (p *ptrDiscover) checkServer() {
|
func (p *ptrDiscover) checkServer() {
|
||||||
bo := backoff.NewBackoff("ptrDiscover", func(format string, args ...any) {}, time.Minute*5)
|
bo := backoff.NewBackoff("ptrDiscover", func(format string, args ...any) {}, time.Minute*5)
|
||||||
m := new(dns.Msg)
|
m := (&ctrld.UpstreamConfig{}).VerifyMsg()
|
||||||
m.SetQuestion(".", dns.TypeNS)
|
|
||||||
ping := func() error {
|
ping := func() error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|||||||
@@ -282,6 +282,35 @@ func Test_Edns0_CacheReply(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/Control-D-Inc/ctrld/issues/255
|
||||||
|
func Test_legacyResolverWithBigExtraSection(t *testing.T) {
|
||||||
|
lanPC, err := net.ListenPacket("udp", "127.0.0.1:0") // 127.0.0.1 is considered LAN (loopback)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to listen on LAN address: %v", err)
|
||||||
|
}
|
||||||
|
lanServer, lanAddr, err := runLocalPacketConnTestServer(t, lanPC, bigExtraSectionHandler())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to run LAN test server: %v", err)
|
||||||
|
}
|
||||||
|
defer lanServer.Shutdown()
|
||||||
|
|
||||||
|
uc := &UpstreamConfig{
|
||||||
|
Name: "Legacy",
|
||||||
|
Type: ResolverTypeLegacy,
|
||||||
|
Endpoint: lanAddr,
|
||||||
|
}
|
||||||
|
uc.Init()
|
||||||
|
r, err := NewResolver(uc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.Resolve(context.Background(), uc.VerifyMsg())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_upstreamTypeFromEndpoint(t *testing.T) {
|
func Test_upstreamTypeFromEndpoint(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -370,6 +399,68 @@ func countHandler(call *atomic.Int64) dns.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mustRR(s string) dns.RR {
|
||||||
|
r, err := dns.NewRR(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func bigExtraSectionHandler() dns.HandlerFunc {
|
||||||
|
return func(w dns.ResponseWriter, msg *dns.Msg) {
|
||||||
|
m := &dns.Msg{
|
||||||
|
Answer: []dns.RR{
|
||||||
|
mustRR(". 7149 IN NS m.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS c.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS e.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS j.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS g.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS k.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS l.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS d.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS h.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS b.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS a.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS f.root-servers.net."),
|
||||||
|
mustRR(". 7149 IN NS i.root-servers.net."),
|
||||||
|
},
|
||||||
|
Extra: []dns.RR{
|
||||||
|
mustRR("m.root-servers.net. 656 IN A 202.12.27.33"),
|
||||||
|
mustRR("m.root-servers.net. 656 IN AAAA 2001:dc3::35"),
|
||||||
|
mustRR("c.root-servers.net. 656 IN A 192.33.4.12"),
|
||||||
|
mustRR("c.root-servers.net. 656 IN AAAA 2001:500:2::c"),
|
||||||
|
mustRR("e.root-servers.net. 656 IN A 192.203.230.10"),
|
||||||
|
mustRR("e.root-servers.net. 656 IN AAAA 2001:500:a8::e"),
|
||||||
|
mustRR("j.root-servers.net. 656 IN A 192.58.128.30"),
|
||||||
|
mustRR("j.root-servers.net. 656 IN AAAA 2001:503:c27::2:30"),
|
||||||
|
mustRR("g.root-servers.net. 656 IN A 192.112.36.4"),
|
||||||
|
mustRR("g.root-servers.net. 656 IN AAAA 2001:500:12::d0d"),
|
||||||
|
mustRR("k.root-servers.net. 656 IN A 193.0.14.129"),
|
||||||
|
mustRR("k.root-servers.net. 656 IN AAAA 2001:7fd::1"),
|
||||||
|
mustRR("l.root-servers.net. 656 IN A 199.7.83.42"),
|
||||||
|
mustRR("l.root-servers.net. 656 IN AAAA 2001:500:9f::42"),
|
||||||
|
mustRR("d.root-servers.net. 656 IN A 199.7.91.13"),
|
||||||
|
mustRR("d.root-servers.net. 656 IN AAAA 2001:500:2d::d"),
|
||||||
|
mustRR("h.root-servers.net. 656 IN A 198.97.190.53"),
|
||||||
|
mustRR("h.root-servers.net. 656 IN AAAA 2001:500:1::53"),
|
||||||
|
mustRR("b.root-servers.net. 656 IN A 170.247.170.2"),
|
||||||
|
mustRR("b.root-servers.net. 656 IN AAAA 2801:1b8:10::b"),
|
||||||
|
mustRR("a.root-servers.net. 656 IN A 198.41.0.4"),
|
||||||
|
mustRR("a.root-servers.net. 656 IN AAAA 2001:503:ba3e::2:30"),
|
||||||
|
mustRR("f.root-servers.net. 656 IN A 192.5.5.241"),
|
||||||
|
mustRR("f.root-servers.net. 656 IN AAAA 2001:500:2f::f"),
|
||||||
|
mustRR("i.root-servers.net. 656 IN A 192.36.148.17"),
|
||||||
|
mustRR("i.root-servers.net. 656 IN AAAA 2001:7fe::53"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Compress = true
|
||||||
|
m.SetReply(msg)
|
||||||
|
w.WriteMsg(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func generateEdns0ClientCookie() string {
|
func generateEdns0ClientCookie() string {
|
||||||
cookie := make([]byte, 8)
|
cookie := make([]byte, 8)
|
||||||
if _, err := rand.Read(cookie); err != nil {
|
if _, err := rand.Read(cookie); err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user