aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/dnsserver/zdirectives.go1
-rw-r--r--core/plugin/zplugin.go1
-rw-r--r--plugin.cfg1
-rw-r--r--plugin/bufsize/README.md30
-rw-r--r--plugin/bufsize/bufsize.go31
-rw-r--r--plugin/bufsize/bufsize_test.go72
-rw-r--r--plugin/bufsize/setup.go52
-rw-r--r--plugin/bufsize/setup_test.go46
8 files changed, 234 insertions, 0 deletions
diff --git a/core/dnsserver/zdirectives.go b/core/dnsserver/zdirectives.go
index 8e2153aad..61d96c633 100644
--- a/core/dnsserver/zdirectives.go
+++ b/core/dnsserver/zdirectives.go
@@ -15,6 +15,7 @@ var Directives = []string{
"tls",
"reload",
"nsid",
+ "bufsize",
"root",
"bind",
"debug",
diff --git a/core/plugin/zplugin.go b/core/plugin/zplugin.go
index 79892235f..90267f29b 100644
--- a/core/plugin/zplugin.go
+++ b/core/plugin/zplugin.go
@@ -11,6 +11,7 @@ import (
_ "github.com/coredns/coredns/plugin/autopath"
_ "github.com/coredns/coredns/plugin/azure"
_ "github.com/coredns/coredns/plugin/bind"
+ _ "github.com/coredns/coredns/plugin/bufsize"
_ "github.com/coredns/coredns/plugin/cache"
_ "github.com/coredns/coredns/plugin/cancel"
_ "github.com/coredns/coredns/plugin/chaos"
diff --git a/plugin.cfg b/plugin.cfg
index 47b9ecb51..d40cf7a33 100644
--- a/plugin.cfg
+++ b/plugin.cfg
@@ -24,6 +24,7 @@ cancel:cancel
tls:tls
reload:reload
nsid:nsid
+bufsize:bufsize
root:root
bind:bind
debug:debug
diff --git a/plugin/bufsize/README.md b/plugin/bufsize/README.md
new file mode 100644
index 000000000..bd1d232d1
--- /dev/null
+++ b/plugin/bufsize/README.md
@@ -0,0 +1,30 @@
+# bufsize
+## Name
+*bufsize* - sizes EDNS0 buffer size to prevent IP fragmentation.
+
+## Description
+*bufsize* limits a requester's UDP payload size.
+It prevents IP fragmentation so that to deal with DNS vulnerability.
+
+## Syntax
+```txt
+bufsize [SIZE]
+```
+
+**[SIZE]** is an int value for setting the buffer size.
+The default value is 512, and the value must be within 512 - 4096.
+Only one argument is acceptable, and it covers both IPv4 and IPv6.
+
+## Examples
+```corefile
+. {
+ bufsize 512
+ forward . 172.31.0.10
+ log
+}
+```
+
+If you run a resolver on 172.31.0.10, the buffer size of incoming query on the resolver will be set to 512 bytes.
+
+## Considerations
+For now, if a client does not use EDNS, this plugin adds OPT RR. \ No newline at end of file
diff --git a/plugin/bufsize/bufsize.go b/plugin/bufsize/bufsize.go
new file mode 100644
index 000000000..1522be894
--- /dev/null
+++ b/plugin/bufsize/bufsize.go
@@ -0,0 +1,31 @@
+// Package bufsize implements a plugin that modifies EDNS0 buffer size.
+package bufsize
+
+import (
+ "context"
+
+ "github.com/coredns/coredns/plugin"
+
+ "github.com/miekg/dns"
+)
+
+// Bufsize implements bufsize plugin.
+type Bufsize struct {
+ Next plugin.Handler
+ Size int
+}
+
+// ServeDNS implements the plugin.Handler interface.
+func (buf Bufsize) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
+ if option := r.IsEdns0(); option != nil {
+ option.SetUDPSize(uint16(buf.Size))
+ } else {
+ // If a client does not use EDNS, add it
+ r.SetEdns0(uint16(buf.Size), false)
+ }
+
+ return plugin.NextOrFailure(buf.Name(), buf.Next, ctx, w, r)
+}
+
+// Name implements the Handler interface.
+func (buf Bufsize) Name() string { return "bufsize" }
diff --git a/plugin/bufsize/bufsize_test.go b/plugin/bufsize/bufsize_test.go
new file mode 100644
index 000000000..3d714d2f1
--- /dev/null
+++ b/plugin/bufsize/bufsize_test.go
@@ -0,0 +1,72 @@
+package bufsize
+
+import (
+ "context"
+ "testing"
+
+ "github.com/coredns/coredns/plugin"
+ "github.com/coredns/coredns/plugin/test"
+ "github.com/coredns/coredns/plugin/whoami"
+
+ "github.com/miekg/dns"
+)
+
+func TestBufsize(t *testing.T) {
+ em := Bufsize{
+ Size: 512,
+ }
+
+ tests := []struct {
+ next plugin.Handler
+ qname string
+ inputBufsize uint16
+ outgoingBufsize uint16
+ expectedErr error
+ }{
+ // This plugin is responsible for limiting outgoing query's bufize
+ {
+ next: whoami.Whoami{},
+ qname: ".",
+ inputBufsize: 1200,
+ outgoingBufsize: 512,
+ expectedErr: nil,
+ },
+ // If EDNS is not enabled, this plugin adds it
+ {
+ next: whoami.Whoami{},
+ qname: ".",
+ outgoingBufsize: 512,
+ expectedErr: nil,
+ },
+ }
+
+ for i, tc := range tests {
+ req := new(dns.Msg)
+ req.SetQuestion(dns.Fqdn(tc.qname), dns.TypeA)
+ req.Question[0].Qclass = dns.ClassINET
+ em.Next = tc.next
+
+ if tc.inputBufsize != 0 {
+ req.SetEdns0(tc.inputBufsize, false)
+ }
+
+ _, err := em.ServeDNS(context.Background(), &test.ResponseWriter{}, req)
+
+ if err != tc.expectedErr {
+ t.Errorf("Test %d: Expected error is %v, but got %v", i, tc.expectedErr, err)
+ }
+
+ if tc.outgoingBufsize != 0 {
+ for _, extra := range req.Extra {
+ if option, ok := extra.(*dns.OPT); ok {
+ b := option.UDPSize()
+ if b != tc.outgoingBufsize {
+ t.Errorf("Test %d: Expected outgoing bufsize is %d, but got %d", i, tc.outgoingBufsize, b)
+ }
+ } else {
+ t.Errorf("Test %d: Not found OPT RR.", i)
+ }
+ }
+ }
+ }
+}
diff --git a/plugin/bufsize/setup.go b/plugin/bufsize/setup.go
new file mode 100644
index 000000000..28586c76e
--- /dev/null
+++ b/plugin/bufsize/setup.go
@@ -0,0 +1,52 @@
+package bufsize
+
+import (
+ "strconv"
+
+ "github.com/coredns/coredns/core/dnsserver"
+ "github.com/coredns/coredns/plugin"
+
+ "github.com/caddyserver/caddy"
+)
+
+func init() { plugin.Register("bufsize", setup) }
+
+func setup(c *caddy.Controller) error {
+ bufsize, err := parse(c)
+ if err != nil {
+ return plugin.Error("bufsize", err)
+ }
+
+ dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
+ return Bufsize{Next: next, Size: bufsize}
+ })
+
+ return nil
+}
+
+func parse(c *caddy.Controller) (int, error) {
+ const defaultBufSize = 512
+ for c.Next() {
+ args := c.RemainingArgs()
+ switch len(args) {
+ case 0:
+ // Nothing specified; use 512 as default
+ return defaultBufSize, nil
+ case 1:
+ // Specified value is needed to verify
+ bufsize, err := strconv.Atoi(args[0])
+ if err != nil {
+ return -1, plugin.Error("bufsize", c.ArgErr())
+ }
+ // Follows RFC 6891
+ if bufsize < 512 || bufsize > 4096 {
+ return -1, plugin.Error("bufsize", c.ArgErr())
+ }
+ return bufsize, nil
+ default:
+ // Only 1 argument is acceptable
+ return -1, plugin.Error("bufsize", c.ArgErr())
+ }
+ }
+ return -1, plugin.Error("bufsize", c.ArgErr())
+}
diff --git a/plugin/bufsize/setup_test.go b/plugin/bufsize/setup_test.go
new file mode 100644
index 000000000..4d1705a05
--- /dev/null
+++ b/plugin/bufsize/setup_test.go
@@ -0,0 +1,46 @@
+package bufsize
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/caddyserver/caddy"
+)
+
+func TestSetupBufsize(t *testing.T) {
+ tests := []struct {
+ input string
+ shouldErr bool
+ expectedData int
+ expectedErrContent string // substring from the expected error. Empty for positive cases.
+ }{
+ {`bufsize`, false, 512, ""},
+ {`bufsize "1232"`, false, 1232, ""},
+ {`bufsize "5000"`, true, -1, "plugin"},
+ {`bufsize "512 512"`, true, -1, "plugin"},
+ {`bufsize "abc123"`, true, -1, "plugin"},
+ }
+
+ for i, test := range tests {
+ c := caddy.NewTestController("dns", test.input)
+ bufsize, err := parse(c)
+
+ if test.shouldErr && err == nil {
+ t.Errorf("Test %d: Expected error but found %s for input %s", i, err, test.input)
+ }
+
+ if err != nil {
+ if !test.shouldErr {
+ t.Errorf("Test %d: Error found for input %s. Error: %v", i, test.input, err)
+ }
+
+ if !strings.Contains(err.Error(), test.expectedErrContent) {
+ t.Errorf("Test %d: Expected error to contain: %v, found error: %v, input: %s", i, test.expectedErrContent, err, test.input)
+ }
+ }
+
+ if !test.shouldErr && bufsize != test.expectedData {
+ t.Errorf("Test %d: Bufsize not correctly set for input %s. Expected: %d, actual: %d", i, test.input, test.expectedData, bufsize)
+ }
+ }
+}