Implement AXFR over TCP and RFC 2136 UPDATE with caller TSIG.
Callers get a session API, typed RR builders, and BIND testcontainer proof so CheckDNS can stay off the DNS wire. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+125
@@ -0,0 +1,125 @@
|
||||
package godns_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
godns "gitea.neitzel.de/konrad/go-dns"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func TestUpdateFallsBackToTCPWhenUDPTruncated(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var udpHits, tcpHits atomic.Int32
|
||||
mux := dns.NewServeMux()
|
||||
mux.HandleFunc("example.test.", func(w dns.ResponseWriter, r *dns.Msg) {
|
||||
if r.IsTsig() == nil {
|
||||
t.Error("UPDATE request missing TSIG")
|
||||
}
|
||||
msg := new(dns.Msg)
|
||||
msg.SetReply(r)
|
||||
if _, ok := w.RemoteAddr().(*net.UDPAddr); ok {
|
||||
udpHits.Add(1)
|
||||
msg.Truncated = true
|
||||
_ = w.WriteMsg(msg)
|
||||
return
|
||||
}
|
||||
tcpHits.Add(1)
|
||||
_ = w.WriteMsg(msg)
|
||||
})
|
||||
|
||||
udp, tcp := startDNSServers(t, mux)
|
||||
client, err := godns.NewClient(udp, "example.test", fixtureTSIG())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = tcp
|
||||
|
||||
rec, err := godns.A("new.example.test", 300, net.ParseIP("192.0.2.99"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
result, err := client.Update(ctx, godns.Add(rec))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.Rcode != "NOERROR" {
|
||||
t.Fatalf("rcode: %s", result.Rcode)
|
||||
}
|
||||
if udpHits.Load() < 1 {
|
||||
t.Fatal("expected a UDP attempt")
|
||||
}
|
||||
if tcpHits.Load() < 1 {
|
||||
t.Fatal("expected TCP fallback")
|
||||
}
|
||||
}
|
||||
|
||||
func startDNSServers(t *testing.T, handler dns.Handler) (udpAddr, tcpAddr string) {
|
||||
t.Helper()
|
||||
|
||||
secrets := map[string]string{"go-dns-test.": fixtureSecret}
|
||||
|
||||
acceptUpdate := func(dh dns.Header) dns.MsgAcceptAction {
|
||||
return dns.MsgAccept
|
||||
}
|
||||
udpSrv := &dns.Server{Addr: "127.0.0.1:0", Net: "udp", Handler: handler, TsigSecret: secrets, MsgAcceptFunc: acceptUpdate}
|
||||
udpReady := make(chan struct{})
|
||||
udpSrv.NotifyStartedFunc = func() { close(udpReady) }
|
||||
go func() { _ = udpSrv.ListenAndServe() }()
|
||||
<-udpReady
|
||||
t.Cleanup(func() { _ = udpSrv.Shutdown() })
|
||||
|
||||
udpAddr = udpSrv.PacketConn.LocalAddr().String()
|
||||
_, port, err := net.SplitHostPort(udpAddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tcpSrv := &dns.Server{Addr: "127.0.0.1:" + port, Net: "tcp", Handler: handler, TsigSecret: secrets, MsgAcceptFunc: acceptUpdate}
|
||||
tcpReady := make(chan struct{})
|
||||
tcpSrv.NotifyStartedFunc = func() { close(tcpReady) }
|
||||
go func() { _ = tcpSrv.ListenAndServe() }()
|
||||
<-tcpReady
|
||||
t.Cleanup(func() { _ = tcpSrv.Shutdown() })
|
||||
|
||||
return udpAddr, tcpSrv.Listener.Addr().String()
|
||||
}
|
||||
|
||||
func TestAddChangeDescribesInsert(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, err := godns.A("www.example.test", 300, net.ParseIP("192.0.2.10"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
change := godns.Add(rec)
|
||||
if change.Action != godns.ActionAdd {
|
||||
t.Fatalf("action: %v", change.Action)
|
||||
}
|
||||
if change.Record.Type != "A" {
|
||||
t.Fatalf("record: %+v", change.Record)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteChangeDescribesRemove(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, err := godns.TXT("bad.example.test", 300, "stale")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
change := godns.Delete(rec)
|
||||
if change.Action != godns.ActionDelete {
|
||||
t.Fatalf("action: %v", change.Action)
|
||||
}
|
||||
if !strings.Contains(change.Record.RData, "stale") {
|
||||
t.Fatalf("rdata: %q", change.Record.RData)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user