feat(secondary): Send NOTIFY messages after zone transfer (#7901)

* feat(secondary): Send NOTIFY messages after zone transfer

- Modified TransferIn() method to accept a transfer.Transfer parameter
- Added NOTIFY message sending after successful zone transfer in secondary plugin
- Updated Update() method to pass the transfer handler through the zone update cycle
- Added comprehensive tests for the secondary notify functionality

Closes #5669

Signed-off-by: liucongran <liucongran327@gmail.com>

* fix(secondary): Fix TransferIn method call in test

Update test to pass nil parameter to TransferIn method after signature change

Signed-off-by: liucongran <liucongran327@gmail.com>

* refactor(secondary): Clean up imports and add helper methods

- Reorder imports for consistency
- Add hasSOA() and getSOA() helper methods to Zone
- Remove unnecessary blank lines in tests

Signed-off-by: liucongran <liucongran327@gmail.com>

* fix(test): Fix variable declaration in secondary test

Change corefile variable assignment to use short declaration syntax (:=)
to fix compilation error.

Signed-off-by: liucongran <liucongran327@gmail.com>

* refactor(secondary): Use getSOA helper method in shouldTransfer

Replace direct SOA access with getSOA() helper method for consistency.

Signed-off-by: liucongran <liucongran327@gmail.com>

---------

Signed-off-by: liucongran <liucongran327@gmail.com>
Co-authored-by: liucongran <liucongran@cestc.cn>
This commit is contained in:
liucongran
2026-03-08 13:15:44 +08:00
committed by GitHub
parent 90a9739478
commit 2daf48e42d
7 changed files with 170 additions and 20 deletions

View File

@@ -1,6 +1,7 @@
package test
import (
"os"
"testing"
"time"
@@ -215,3 +216,116 @@ www IN AAAA ::1
}
}
}
func TestSecondaryZoneNotify(t *testing.T) {
// Now spin up the master server
name, rm, err := test.TempFile(".", `$ORIGIN example.org.
@ 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. (
2017042745 ; serial
7200 ; refresh (2 hours)
3600 ; retry (1 hour)
1209600 ; expire (2 weeks)
3600 ; minimum (1 hour)
)
3600 IN NS a.iana-servers.net.
3600 IN NS b.iana-servers.net.
`)
if err != nil {
t.Fatalf("Failed to create zone: %s", err)
}
defer rm()
corefileMaster := `example.org:53553 {
bind 127.0.0.1
file ` + name + ` {
reload 0.01s
}
transfer {
to 127.0.0.1:53554
}
}`
master, _, _, err := CoreDNSServerAndPorts(corefileMaster)
if err != nil {
t.Fatalf("Could not get CoreDNS serving instance: %s", err)
}
defer master.Stop()
corefileSecondary := `example.org:53554 {
bind 127.0.0.1
secondary {
transfer from 127.0.0.1:53553
}
transfer {
to 127.0.0.1:53555
}
}`
secondary, _, _, err := CoreDNSServerAndPorts(corefileSecondary)
if err != nil {
t.Fatalf("Could not get CoreDNS serving instance: %s", err)
}
defer secondary.Stop()
corefile := `example.org:53555 {
bind 127.0.0.1
secondary {
transfer from 127.0.0.1:53554
}
}`
svr, udp, _, err := CoreDNSServerAndPorts(corefile)
if err != nil {
t.Fatalf("Could not get CoreDNS serving instance: %s", err)
}
defer svr.Stop()
m := new(dns.Msg)
m.SetQuestion("example.org.", dns.TypeSOA)
var r *dns.Msg
// This is now async; we need to wait for it to be transferred.
for range 10 {
r, _ = dns.Exchange(m, udp)
if len(r.Answer) != 0 {
break
}
time.Sleep(1000 * time.Microsecond)
}
if len(r.Answer) == 0 {
t.Fatalf("Expected answer section")
}
m = new(dns.Msg)
m.SetQuestion("www.example.org.", dns.TypeA)
r, _ = dns.Exchange(m, udp)
if len(r.Answer) != 0 {
t.Fatalf("Expected no answer section, got %d answers", len(r.Answer))
}
os.WriteFile(name, []byte(`$ORIGIN example.org.
@ 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. (
2017042746 ; serial
7200 ; refresh (2 hours)
3600 ; retry (1 hour)
1209600 ; expire (2 weeks)
3600 ; minimum (1 hour)
)
3600 IN NS a.iana-servers.net.
3600 IN NS b.iana-servers.net.
www IN A 127.0.0.1
`), 0644)
// This is now async; we need to wait for it to be transferred.
for range 10 {
r, _ = dns.Exchange(m, udp)
if len(r.Answer) != 0 {
break
}
time.Sleep(1000 * time.Microsecond)
}
if len(r.Answer) != 1 {
t.Fatalf("Expected one RR in answer section got %d", len(r.Answer))
}
}