From c7790a8d9f31afece8b865293308a01263618031 Mon Sep 17 00:00:00 2001 From: Eugene Bujak Date: Wed, 26 Sep 2018 18:27:31 +0300 Subject: [PATCH] coredns plugin -- Add option "blocked_ttl" that can change default nxdomain response TTL --- config.go | 2 ++ coredns_plugin/coredns_plugin.go | 25 ++++++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/config.go b/config.go index 5265a218..8b9d1c5c 100644 --- a/config.go +++ b/config.go @@ -40,6 +40,7 @@ type coreDNSConfig struct { SafeSearchEnabled bool `yaml:"safesearch_enabled"` ParentalEnabled bool `yaml:"parental_enabled"` ParentalSensitivity int `yaml:"parental_sensitivity"` + BlockedResponseTTL int `yaml:"blocked_response_ttl"` QueryLogEnabled bool `yaml:"querylog_enabled"` Pprof string `yaml:"-"` Cache string `yaml:"-"` @@ -70,6 +71,7 @@ var config = configuration{ FilterFile: "dnsfilter.txt", // only filename, no path FilteringEnabled: true, SafeBrowsingEnabled: true, + BlockedResponseTTL: 60, // in seconds QueryLogEnabled: true, UpstreamDNS: defaultDNS, Cache: "cache", diff --git a/coredns_plugin/coredns_plugin.go b/coredns_plugin/coredns_plugin.go index 09b64a9e..0c321a4e 100644 --- a/coredns_plugin/coredns_plugin.go +++ b/coredns_plugin/coredns_plugin.go @@ -54,11 +54,13 @@ type plug struct { SafeBrowsingBlockHost string ParentalBlockHost string QueryLogEnabled bool + BlockedTTL uint32 // in seconds, default 3600 } var defaultPlugin = plug{ SafeBrowsingBlockHost: "safebrowsing.block.dns.adguard.com", ParentalBlockHost: "family.block.dns.adguard.com", + BlockedTTL: 3600, // in seconds } func newDNSCounter(name string, help string) prometheus.Counter { @@ -128,6 +130,15 @@ func setupPlugin(c *caddy.Controller) (*plug, error) { } p.ParentalBlockHost = c.Val() } + case "blocked_ttl": + if !c.NextArg() { + return nil, c.ArgErr() + } + blockttl, err := strconv.ParseUint(c.Val(), 10, 32) + if err != nil { + return nil, c.ArgErr() + } + p.BlockedTTL = uint32(blockttl) case "querylog": p.QueryLogEnabled = true onceQueryLog.Do(func() { @@ -294,7 +305,7 @@ func (p *plug) replaceHostWithValAndReply(ctx context.Context, w dns.ResponseWri log.Println("Will give", val, "instead of", host) if addr != nil { // this is an IP address, return it - result, err := dns.NewRR(host + " A " + val) + result, err := dns.NewRR(fmt.Sprintf("%s %d A %s", host, p.BlockedTTL, val)) if err != nil { log.Printf("Got error %s\n", err) return dns.RcodeServerFailure, fmt.Errorf("plugin/dnsfilter: %s", err) @@ -334,9 +345,9 @@ func (p *plug) replaceHostWithValAndReply(ctx context.Context, w dns.ResponseWri // generate SOA record that makes DNS clients cache NXdomain results // the only value that is important is TTL in header, other values like refresh, retry, expire and minttl are irrelevant -func genSOA(r *dns.Msg) []dns.RR { +func (p *plug) genSOA(r *dns.Msg) []dns.RR { zone := r.Question[0].Name - header := dns.RR_Header{Name: zone, Rrtype: dns.TypeSOA, Ttl: 3600, Class: dns.ClassINET} + header := dns.RR_Header{Name: zone, Rrtype: dns.TypeSOA, Ttl: p.BlockedTTL, Class: dns.ClassINET} Mbox := "hostmaster." if zone[0] != '.' { @@ -352,12 +363,12 @@ func genSOA(r *dns.Msg) []dns.RR { return []dns.RR{soa} } -func writeNXdomain(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { +func (p *plug) writeNXdomain(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := request.Request{W: w, Req: r, Context: ctx} m := new(dns.Msg) m.SetRcode(state.Req, dns.RcodeNameError) m.Authoritative, m.RecursionAvailable, m.Compress = true, true, true - m.Ns = genSOA(r) + m.Ns = p.genSOA(r) state.SizeAndDo(m) err := state.W.WriteMsg(m) @@ -389,7 +400,7 @@ func (p *plug) serveDNSInternal(ctx context.Context, w dns.ResponseWriter, r *dn // it is, if it's a loopback host, reply with NXDOMAIN // TODO: research if it's better than 127.0.0.1 if false && val.IsLoopback() { - rcode, err := writeNXdomain(ctx, w, r) + rcode, err := p.writeNXdomain(ctx, w, r) if err != nil { return rcode, dnsfilter.Result{}, err } @@ -430,7 +441,7 @@ func (p *plug) serveDNSInternal(ctx context.Context, w dns.ResponseWriter, r *dn return rcode, result, err case dnsfilter.FilteredBlackList: // return NXdomain - rcode, err := writeNXdomain(ctx, w, r) + rcode, err := p.writeNXdomain(ctx, w, r) if err != nil { return rcode, dnsfilter.Result{}, err }