Each view's match-clients starts with "key jarl-view-NAME" (after
"!key" for the views listed after it), so a query signed with a view's
key lands in that view from any address. The secrets are derived from a
random seed in Jarl's database. The delegation check signs its queries
to this server's own addresses with the key of the zone's view: before,
they got whichever view matched the server's address, usually internal.
jarl view key / GET /views/{id}/key show a key for dig -k (tsig:write,
audited). jarl-view- key names are reserved; the importer drops view
keys from a configuration Jarl wrote.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
53 lines
1.7 KiB
Go
53 lines
1.7 KiB
Go
package nscheck
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"net/netip"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
// A query to this host's own address is signed with LocalKey, so a server
|
|
// with views answers from the view that key selects.
|
|
func TestLocalKey(t *testing.T) {
|
|
zone := "example.com."
|
|
key := &Key{Name: "jarl-view-external.", Algorithm: "hmac-sha256", Secret: "c2VjcmV0LXNlY3JldC1zZWNyZXQtc2VjcmV0LXNlY3I="}
|
|
pc, err := net.ListenPacket("udp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Skip(err)
|
|
}
|
|
_, port, _ := net.SplitHostPort(pc.LocalAddr().String())
|
|
srv := &dns.Server{PacketConn: pc, TsigSecret: map[string]string{key.Name: key.Secret},
|
|
Handler: dns.HandlerFunc(func(w dns.ResponseWriter, req *dns.Msg) {
|
|
// Signed with the view key: the "external" view's serial.
|
|
serial := "1"
|
|
signed := req.IsTsig() != nil && w.TsigStatus() == nil
|
|
if signed {
|
|
serial = "2"
|
|
}
|
|
m := new(dns.Msg)
|
|
m.SetReply(req)
|
|
m.Authoritative = true
|
|
m.Answer = []dns.RR{rr(zone + " 3600 IN SOA ns1." + zone + " admin." + zone + " " + serial + " 3600 900 1209600 300")}
|
|
if signed {
|
|
m.SetTsig(key.Name, dns.HmacSHA256, 300, time.Now().Unix())
|
|
}
|
|
w.WriteMsg(m)
|
|
})}
|
|
go srv.ActivateAndServe()
|
|
t.Cleanup(func() { srv.Shutdown() })
|
|
|
|
ref := uint32(2)
|
|
c := &Checker{Timeout: time.Second, Port: port, IsLocal: func(netip.Addr) bool { return false }}
|
|
if res := c.Serials(context.Background(), zone, &ref, []Target{{Addresses: []string{"127.0.0.1"}}}); res[0].Status != "behind" {
|
|
t.Errorf("unsigned: %+v (want the other view's serial)", res[0])
|
|
}
|
|
c.LocalKey = key
|
|
if res := c.Serials(context.Background(), zone, &ref, []Target{{Addresses: []string{"127.0.0.1"}}}); res[0].Status != "in_sync" {
|
|
t.Errorf("signed with the view key: %+v", res[0])
|
|
}
|
|
}
|