From 0440e54bcf8cf2b1b3e7c03ae6f3e446b99a2dfa Mon Sep 17 00:00:00 2001 From: Ville Vesilehto Date: Fri, 19 Sep 2025 05:14:51 +0300 Subject: [PATCH] fix(dnstap): add bounds for plugin args (#7557) Validate dnstap writebuffer (MiB) and queue (x10k) args. Reject non-integers and out-of-range values with clear errors. Updated plugin documentation and tests. Signed-off-by: Ville Vesilehto --- plugin/dnstap/README.md | 5 ++++- plugin/dnstap/setup.go | 29 ++++++++++++++++++++++++++--- plugin/dnstap/setup_test.go | 8 ++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/plugin/dnstap/README.md b/plugin/dnstap/README.md index 5ec188d3b..4d53612cf 100644 --- a/plugin/dnstap/README.md +++ b/plugin/dnstap/README.md @@ -25,11 +25,14 @@ dnstap SOCKET [full] [writebuffer] [queue] { * **SOCKET** is the socket (path) supplied to the dnstap command line tool. * `full` to include the wire-format DNS message. +* **writebuffer** sets the TCP write buffer multiplier in MiB. Valid range: [1, 1024]. +* **queue** sets the queue multiplier, applied to 10,000 messages. Valid range: [1, 4096]. * **IDENTITY** to override the identity of the server. Defaults to the hostname. * **VERSION** to override the version field. Defaults to the CoreDNS version. * **EXTRA** to define "extra" field in dnstap payload, [metadata](../metadata/) replacement available here. * `skipverify` to skip tls verification during connection. Default to be secure + ## Examples Log information about client requests and responses to */tmp/dnstap.sock*. @@ -38,7 +41,7 @@ Log information about client requests and responses to */tmp/dnstap.sock*. dnstap /tmp/dnstap.sock ~~~ -Log information about client requests and responses and tcp write buffer is 1024*Mb and queue is 2048*10000. +Log information about client requests and responses with a custom TCP write buffer (1024 MiB) and queue capacity (2048 x 10000). ~~~ txt dnstap /tmp/dnstap.sock full 1024 2048 diff --git a/plugin/dnstap/setup.go b/plugin/dnstap/setup.go index 6e85a4a2c..6e758a2ea 100644 --- a/plugin/dnstap/setup.go +++ b/plugin/dnstap/setup.go @@ -17,6 +17,14 @@ var log = clog.NewWithPlugin("dnstap") func init() { plugin.Register("dnstap", setup) } +const ( + // Upper bounds chosen to keep memory use and kernel socket buffer requests reasonable + // while allowing large configurations. Write buffer multiple is in MiB units; queue + // multiple is applied to 10,000 messages. See plugin README for parameter semantics. + maxMultipleTcpWriteBuf = 1024 // up to 1 GiB write buffer per TCP connection + maxMultipleQueue = 4096 // up to 40,960,000 enqueued messages +) + func parseConfig(c *caddy.Controller) ([]*Dnstap, error) { dnstaps := []*Dnstap{} @@ -37,11 +45,26 @@ func parseConfig(c *caddy.Controller) ([]*Dnstap, error) { endpoint := args[0] if len(args) >= 3 { - d.MultipleTcpWriteBuf, _ = strconv.Atoi(args[2]) + tcpWriteBuf := args[2] + if v, err := strconv.Atoi(tcpWriteBuf); err == nil { + if v < 1 || v > maxMultipleTcpWriteBuf { + return nil, c.Errf("dnstap: MultipleTcpWriteBuf must be between 1 and %d (MiB units): %d", maxMultipleTcpWriteBuf, v) + } + d.MultipleTcpWriteBuf = v + } else { + return nil, c.Errf("dnstap: invalid MultipleTcpWriteBuf %q: %v", tcpWriteBuf, err) + } } - if len(args) >= 4 { - d.MultipleQueue, _ = strconv.Atoi(args[3]) + qSize := args[3] + if v, err := strconv.Atoi(qSize); err == nil { + if v < 1 || v > maxMultipleQueue { + return nil, c.Errf("dnstap: MultipleQueue must be between 1 and %d (x10k messages): %d", maxMultipleQueue, v) + } + d.MultipleQueue = v + } else { + return nil, c.Errf("dnstap: invalid MultipleQueue %q: %v", qSize, err) + } } var dio *dio diff --git a/plugin/dnstap/setup_test.go b/plugin/dnstap/setup_test.go index 8aabc7eb1..f2edae5aa 100644 --- a/plugin/dnstap/setup_test.go +++ b/plugin/dnstap/setup_test.go @@ -54,6 +54,14 @@ func TestConfig(t *testing.T) { {"dnstap dnstap.sock {\nidentity\n}\n", true, []results{{"dnstap.sock", false, "unix", []byte(hostname), []byte("-"), "", 1, 1}}}, {"dnstap dnstap.sock {\nversion\n}\n", true, []results{{"dnstap.sock", false, "unix", []byte(hostname), []byte("-"), "", 1, 1}}}, {"dnstap dnstap.sock {\nextra\n}\n", true, []results{{"dnstap.sock", false, "unix", []byte(hostname), []byte("-"), "", 1, 1}}}, + // Limits and parsing for writebuffer (MiB) and queue (x10k) + {"dnstap dnstap.sock full 1024 2048", false, []results{{"dnstap.sock", true, "unix", []byte(hostname), []byte("-"), "", 1024, 2048}}}, + {"dnstap dnstap.sock full 1025 1", true, []results{{"dnstap.sock", true, "unix", []byte(hostname), []byte("-"), "", 1, 1}}}, + {"dnstap dnstap.sock full 1 4097", true, []results{{"dnstap.sock", true, "unix", []byte(hostname), []byte("-"), "", 1, 1}}}, + {"dnstap dnstap.sock full 0 10", true, []results{{"dnstap.sock", true, "unix", []byte(hostname), []byte("-"), "", 1, 1}}}, + {"dnstap dnstap.sock full 10 0", true, []results{{"dnstap.sock", true, "unix", []byte(hostname), []byte("-"), "", 1, 1}}}, + {"dnstap dnstap.sock full x 10", true, []results{{"dnstap.sock", true, "unix", []byte(hostname), []byte("-"), "", 1, 1}}}, + {"dnstap dnstap.sock full 10 y", true, []results{{"dnstap.sock", true, "unix", []byte(hostname), []byte("-"), "", 1, 1}}}, } for i, tc := range tests { c := caddy.NewTestController("dns", tc.in)