Files
coredns/plugin/file/svcb_test.go

225 lines
6.5 KiB
Go
Raw Permalink Normal View History

package file
import (
"context"
"strings"
"testing"
"github.com/coredns/coredns/plugin/pkg/dnstest"
"github.com/coredns/coredns/plugin/test"
"github.com/miekg/dns"
)
var svcbAuth = []dns.RR{
test.NS("example.com. 1800 IN NS ns.example.com."),
}
var svcbTestCases = []test.Case{
{
// Basic SVCB query with additional section glue for in-bailiwick target
Qname: "_8443._foo.example.com.", Qtype: dns.TypeSVCB,
Answer: []dns.RR{
test.SVCB("_8443._foo.example.com. 1800 IN SVCB 1 svc-target.example.com. alpn=\"h2,h3\" port=\"8443\""),
},
Ns: svcbAuth,
Extra: []dns.RR{
test.A("svc-target.example.com. 1800 IN A 192.0.2.10"),
test.AAAA("svc-target.example.com. 1800 IN AAAA 2001:db8::10"),
},
},
{
// Basic HTTPS query with additional section glue for in-bailiwick target
Qname: "www.example.com.", Qtype: dns.TypeHTTPS,
Answer: []dns.RR{
test.HTTPS("www.example.com. 1800 IN HTTPS 1 svc-target.example.com. alpn=\"h2,h3\""),
},
Ns: svcbAuth,
Extra: []dns.RR{
test.A("svc-target.example.com. 1800 IN A 192.0.2.10"),
test.AAAA("svc-target.example.com. 1800 IN AAAA 2001:db8::10"),
},
},
{
// SVCB AliasMode (Priority=0) — glue still added for in-bailiwick target
Qname: "_alias._foo.example.com.", Qtype: dns.TypeSVCB,
Answer: []dns.RR{
test.SVCB("_alias._foo.example.com. 1800 IN SVCB 0 svc-target.example.com."),
},
Ns: svcbAuth,
Extra: []dns.RR{
test.A("svc-target.example.com. 1800 IN A 192.0.2.10"),
test.AAAA("svc-target.example.com. 1800 IN AAAA 2001:db8::10"),
},
},
{
// Wildcard SVCB expansion (no additional section — wildcards don't run additionalProcessing)
Qname: "_http._tcp.example.com.", Qtype: dns.TypeSVCB,
Answer: []dns.RR{
test.SVCB("_http._tcp.example.com. 1800 IN SVCB 1 svc-target.example.com. port=\"443\""),
},
Ns: svcbAuth,
},
{
// NoData: existing name, no SVCB record
Qname: "svc-target.example.com.", Qtype: dns.TypeSVCB,
Ns: []dns.RR{
test.SOA("example.com. 1800 IN SOA ns.example.com. admin.example.com. 2024010100 14400 3600 604800 14400"),
},
},
{
// NXDOMAIN
Qname: "nonexistent.example.com.", Qtype: dns.TypeSVCB,
Rcode: dns.RcodeNameError,
Ns: []dns.RR{
test.SOA("example.com. 1800 IN SOA ns.example.com. admin.example.com. 2024010100 14400 3600 604800 14400"),
},
},
}
func TestLookupSVCB(t *testing.T) {
zone, err := Parse(strings.NewReader(dbSVCBExample), testSVCBOrigin, "stdin", 0)
if err != nil {
t.Fatalf("Expected no error when reading zone, got %q", err)
}
fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{testSVCBOrigin: zone}, Names: []string{testSVCBOrigin}}}
ctx := context.TODO()
for _, tc := range svcbTestCases {
m := tc.Msg()
rec := dnstest.NewRecorder(&test.ResponseWriter{})
_, err := fm.ServeDNS(ctx, rec, m)
if err != nil {
t.Errorf("Expected no error for %q/%d, got %v", tc.Qname, tc.Qtype, err)
continue
}
resp := rec.Msg
if err := test.SortAndCheck(resp, tc); err != nil {
t.Errorf("Test %q/%d: %v", tc.Qname, tc.Qtype, err)
}
}
}
func TestSVCBTargetNormalization(t *testing.T) {
// Zone with mixed-case SVCB target — should be lowercased on insert
const dbMixedCase = `
$TTL 30M
$ORIGIN example.com.
@ IN SOA ns.example.com. admin.example.com. ( 2024010100 14400 3600 604800 14400 )
IN NS ns.example.com.
ns IN A 192.0.2.1
svc IN A 192.0.2.10
_foo IN SVCB 1 SVC.Example.COM. alpn=h2
`
zone, err := Parse(strings.NewReader(dbMixedCase), testSVCBOrigin, "stdin", 0)
if err != nil {
t.Fatalf("Expected no error when reading zone, got %q", err)
}
fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{testSVCBOrigin: zone}, Names: []string{testSVCBOrigin}}}
ctx := context.TODO()
m := new(dns.Msg)
m.SetQuestion("_foo.example.com.", dns.TypeSVCB)
rec := dnstest.NewRecorder(&test.ResponseWriter{})
_, err = fm.ServeDNS(ctx, rec, m)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
resp := rec.Msg
if len(resp.Answer) != 1 {
t.Fatalf("Expected 1 answer, got %d", len(resp.Answer))
}
svcb, ok := resp.Answer[0].(*dns.SVCB)
if !ok {
t.Fatalf("Expected SVCB record, got %T", resp.Answer[0])
}
if svcb.Target != "svc.example.com." {
t.Errorf("Expected lowercased target %q, got %q", "svc.example.com.", svcb.Target)
}
// Verify additional section contains glue (target was normalized so lookup works)
if len(resp.Extra) != 1 {
t.Fatalf("Expected 1 extra record (A glue), got %d", len(resp.Extra))
}
}
func TestSVCBPrivateKeys(t *testing.T) {
// Test DNS-AID private-use SvcParamKeys (65400-65408) round-trip
zone, err := Parse(strings.NewReader(dbSVCBExample), testSVCBOrigin, "stdin", 0)
if err != nil {
t.Fatalf("Expected no error when reading zone, got %q", err)
}
fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{testSVCBOrigin: zone}, Names: []string{testSVCBOrigin}}}
ctx := context.TODO()
m := new(dns.Msg)
m.SetQuestion("_dnsaid.example.com.", dns.TypeHTTPS)
rec := dnstest.NewRecorder(&test.ResponseWriter{})
_, err = fm.ServeDNS(ctx, rec, m)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
resp := rec.Msg
if len(resp.Answer) != 1 {
t.Fatalf("Expected 1 answer, got %d", len(resp.Answer))
}
https, ok := resp.Answer[0].(*dns.HTTPS)
if !ok {
t.Fatalf("Expected HTTPS record, got %T", resp.Answer[0])
}
// Verify private-use keys survived the round-trip
rr := https.String()
for _, key := range []string{"key65400=", "key65401=", "key65406="} {
if !strings.Contains(rr, key) {
t.Errorf("Expected response to contain %s, got: %s", key, rr)
}
}
}
const testSVCBOrigin = "example.com."
const dbSVCBExample = `
$TTL 30M
$ORIGIN example.com.
@ IN SOA ns.example.com. admin.example.com. (
2024010100 ; serial
14400 ; refresh (4 hours)
3600 ; retry (1 hour)
604800 ; expire (1 week)
14400 ; minimum (4 hours)
)
IN NS ns.example.com.
; A/AAAA records for glue
ns IN A 192.0.2.1
svc-target IN A 192.0.2.10
IN AAAA 2001:db8::10
; SVCB ServiceMode with in-bailiwick target (tests additional section processing)
_8443._foo IN SVCB 1 svc-target.example.com. alpn=h2,h3 port=8443
; HTTPS ServiceMode with in-bailiwick target
www IN HTTPS 1 svc-target.example.com. alpn=h2,h3
; SVCB AliasMode (Priority=0)
_alias._foo IN SVCB 0 svc-target.example.com.
; Wildcard SVCB
*._tcp IN SVCB 1 svc-target.example.com. port=443
; DNS-AID private-use keys (65400-65408)
_dnsaid IN HTTPS 1 svc-target.example.com. alpn=h2 key65400="https://aid.example.com/cap" key65401="sha256:e3b0c44298fc" key65406="apphub-psc"
`