Skip to content

Commit

Permalink
Merge branch 'contrib-add-nxdomain-flag'
Browse files Browse the repository at this point in the history
  • Loading branch information
icyflame committed Jul 15, 2024
2 parents 51e21f5 + 006c38a commit b6f454d
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 21 deletions.
10 changes: 6 additions & 4 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,18 @@ You can include blocker in the CoreDNS code just as you would include any other

** Corefile

The =blocker= directive inside Corefile requires three arguments. The first argument is the absolute
The =blocker= directive inside Corefile requires four arguments. The first argument is the absolute
path to the blocklist file. The second argument is the frequency at which the blocklist file is
checked for updates. The third argument is the type of blocklist file (=hosts= and =abp= are the
only two values which are supported at this time.)
only two values which are supported at this time.) The fourth argument is the response type from
the plugin, either =empty= for a valid DNS response with 0.0.0.0 or ::6 or =nxdomain= to respond
with a DNS empty response.

The frequency is specified as a string and the value should be a valid argument of the
[[https://pkg.go.dev/time#ParseDuration][time.ParseDuration]] function.

#+begin_src conf
blocker /home/user/blocklist_file 1h abp
blocker /home/user/blocklist_file 1h abp empty
#+end_src

The following is a sample Corefile including the =blocker= directive. It will block domains that are
Expand All @@ -82,7 +84,7 @@ specified in the blocklist and forward everything else to a full DNS server.
log . "{common} {/blocker/request-blocked}"

# blocker blocks domains which are specified in the blocklist
blocker /home/user/blocklist_file 1h abp
blocker /home/user/blocklist_file 1h abp empty

# forward handles any request that is not blocked by blocker
forward . 127.0.0.1:9053
Expand Down
44 changes: 32 additions & 12 deletions blocker.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,18 @@ import (
)

type Blocker struct {
Next plugin.Handler
Decider BlockDomainsDecider
Next plugin.Handler
Decider BlockDomainsDecider
ResponseType string
}

type ResponseType string

const (
ResponseType_Empty ResponseType = "empty"
ResponseType_NXDOMAIN ResponseType = "nxdomain"
)

const MetadataRequestBlocked = "blocker/request-blocked"

// Metadata implements the Metadata plugin's required interface in the blocker function.
Expand Down Expand Up @@ -57,17 +65,29 @@ func (b Blocker) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
// IPv6
domain := question.Name
if b.Decider.IsDomainBlocked(domain) {
response := &dns.Msg{
Answer: []dns.RR{
GetEmptyAnswerForQuestionType(questionType, domain),
},
switch ResponseType(b.ResponseType) {
case ResponseType_Empty:
response := &dns.Msg{
Answer: []dns.RR{
GetEmptyAnswerForQuestionType(questionType, domain),
},
}
response.SetReply(r)
w.WriteMsg(response)
metadata.SetValueFunc(ctx, MetadataRequestBlocked, func() string {
return "YES"
})
return dns.RcodeSuccess, nil

case ResponseType_NXDOMAIN:
response := &dns.Msg{}
response.SetRcode(r, dns.RcodeNameError)
w.WriteMsg(response)
metadata.SetValueFunc(ctx, MetadataRequestBlocked, func() string {
return "YES"
})
return dns.RcodeNameError, nil
}
response.SetReply(r)
w.WriteMsg(response)
metadata.SetValueFunc(ctx, MetadataRequestBlocked, func() string {
return "YES"
})
return dns.RcodeSuccess, nil
}

return b.Next.ServeDNS(ctx, w, r)
Expand Down
21 changes: 16 additions & 5 deletions setup.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package blocker

import (
"fmt"

"github.com/coredns/caddy"
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin"
clog "github.com/coredns/coredns/plugin/pkg/log"
)

const PluginName = "blocker"
const RequiredArgs = 3
const RequiredArgs = 4

func init() {
plugin.Register(PluginName, setup)
Expand All @@ -24,18 +26,26 @@ func setup(c *caddy.Controller) error {
if len(args) < RequiredArgs {
// Any errors returned from this setup function should be wrapped with plugin.Error, so we
// can present a slightly nicer error message to the user.
return plugin.Error(PluginName, c.ArgErr())
return plugin.Error(PluginName, c.Errf("number of arguments is less than the required count: given: %d, required: %d", len(args), RequiredArgs))
}

blocklistFilePath := args[0]
blocklistUpdateFrequency := args[1]
blocklistType := args[2]
if blocklistType != string(BlocklistType_Hosts) && blocklistType != string(BlocklistType_ABP) {
return plugin.Error(PluginName, c.Errf("blocklist type is not one of the allowed values: %s, %s", BlocklistType_Hosts, BlocklistType_ABP))
}

blocklistResponseType := args[3]
if blocklistResponseType != string(ResponseType_Empty) && blocklistResponseType != string(ResponseType_NXDOMAIN) {
return plugin.Error(PluginName, c.Errf("blocklist response type is not one of the allowed values: %s, %s", ResponseType_Empty, ResponseType_NXDOMAIN))
}

logger := clog.NewWithPlugin(PluginName)

decider, shutdownHooks, err := PrepareBlocklist(blocklistFilePath, blocklistUpdateFrequency, blocklistType, logger)
if err != nil {
return plugin.Error(PluginName, err)
return plugin.Error(PluginName, fmt.Errorf("could not prepare blocklist in memory > %w", err))
}

for _, hook := range shutdownHooks {
Expand All @@ -45,8 +55,9 @@ func setup(c *caddy.Controller) error {
// Add the Plugin to CoreDNS, so Servers can use it in their plugin chain.
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
return Blocker{
Next: next,
Decider: decider,
Next: next,
Decider: decider,
ResponseType: blocklistResponseType,
}
})

Expand Down

0 comments on commit b6f454d

Please sign in to comment.