| author | Alberto Bertogli
<albertito@blitiri.com.ar> 2026-10-23 19:26:19 UTC |
| committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2026-10-23 19:28:59 UTC |
| parent | 1416dd920cad0e8d286a9df4d7d744cec1d188cd |
| internal/dnsserver/caching_test.go | +11 | -1 |
| internal/dnsserver/resolver.go | +18 | -0 |
diff --git a/internal/dnsserver/caching_test.go b/internal/dnsserver/caching_test.go index d4a10a3..168163a 100644 --- a/internal/dnsserver/caching_test.go +++ b/internal/dnsserver/caching_test.go @@ -4,6 +4,7 @@ package dnsserver import ( "fmt" + "net" "reflect" "strconv" "strings" @@ -188,10 +189,19 @@ func TestCacheBypass(t *testing.T) { ednsV1.SetEdns0(4096, false) ednsV1.IsEdns0().SetVersion(1) + ecs := newQuery("test.", dns.TypeA) + ecs.SetEdns0(4096, false) + ecs.IsEdns0().Option = append(ecs.IsEdns0().Option, &dns.EDNS0_SUBNET{ + Code: dns.EDNS0SUBNET, + Family: 1, + SourceNetmask: 24, + Address: net.ParseIP("192.0.2.0").To4(), + }) + tr := trace.New("test", "TestCacheBypass") defer tr.Finish() - for _, req := range []*dns.Msg{multi, notify, ednsV1} { + for _, req := range []*dns.Msg{multi, notify, ednsV1, ecs} { resetStats() r.LastQuery = nil if _, err := c.Query(req, tr); err != nil { diff --git a/internal/dnsserver/resolver.go b/internal/dnsserver/resolver.go index 936f3ec..2087c5c 100644 --- a/internal/dnsserver/resolver.go +++ b/internal/dnsserver/resolver.go @@ -256,11 +256,29 @@ func canUseCache(r *dns.Msg) error { // We only support EDNS version 0 in our replies. Let the upstream // handle other versions (it should reply with BADVERS). return fmt.Errorf("EDNS version %d != 0", opt.Version()) + } else if hasClientSubnet(opt) { + // The answer may be specific to the client's chosen subnet, so it + // should not be served to others. + return fmt.Errorf("has EDNS client subnet") } return nil } +// hasClientSubnet returns true if the OPT record (which may be nil) has an +// EDNS Client Subnet option (RFC 7871). +func hasClientSubnet(opt *dns.OPT) bool { + if opt == nil { + return false + } + for _, o := range opt.Option { + if o.Option() == dns.EDNS0SUBNET { + return true + } + } + return false +} + func wantToCache(question dns.Question, reply *dns.Msg) error { if reply.Rcode != dns.RcodeSuccess { return fmt.Errorf("unsuccessful query")