From 90a973947809edb089b3eda1371e71ab230a3ba6 Mon Sep 17 00:00:00 2001 From: Ville Vesilehto Date: Fri, 6 Mar 2026 21:50:24 +0200 Subject: [PATCH] chore(lint): bump golangci-lint to v2.11.1 (#7905) - Added nolint to plugin/auto/walk.go to avoid a symlink/TOCTOU warning, as it needs to follow symlink. - Replaced a few flagged integer conversions with safe equivalents in cache hashing, reuseport socket setup, and TLS arg handling - Preallocated response rule slices in plugin/rewrite/name.go - Replaced WriteString(fmt.Sprintf/Sprintln(...)) with direct fmt.Fprint* calls - Removed stale nolint directives from code and tests that are no longer needed Signed-off-by: Ville Vesilehto --- .github/workflows/golangci-lint.yml | 2 +- core/dnsserver/onstartup.go | 8 ++++---- core/dnsserver/server_quic.go | 1 - plugin/auto/walk.go | 2 +- plugin/cache/cache.go | 6 ++++-- plugin/file/file.go | 1 - plugin/k8s_external/transfer_test.go | 4 ++-- plugin/kubernetes/xfr_test.go | 2 +- plugin/pkg/reuseport/listen_reuseport.go | 8 +++++++- plugin/pkg/tls/tls.go | 16 +++++++++++++--- plugin/rewrite/name.go | 12 +++++++----- test/file_xfr_test.go | 2 +- 12 files changed, 41 insertions(+), 23 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 36347ae0c..a2ff64e78 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -20,4 +20,4 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 with: - version: v2.9.0 + version: v2.11.1 diff --git a/core/dnsserver/onstartup.go b/core/dnsserver/onstartup.go index 90a270bad..6b84d6b8d 100644 --- a/core/dnsserver/onstartup.go +++ b/core/dnsserver/onstartup.go @@ -35,23 +35,23 @@ func startUpZones(protocol, addr string, zones map[string][]*Config) string { var sb strings.Builder for _, zone := range keys { if !checkZoneSyntax(zone) { - sb.WriteString(fmt.Sprintf("Warning: Domain %q does not follow RFC1035 preferred syntax\n", zone)) + fmt.Fprintf(&sb, "Warning: Domain %q does not follow RFC1035 preferred syntax\n", zone) } // split addr into protocol, IP and Port _, ip, port, err := SplitProtocolHostPort(addr) if err != nil { // this should not happen, but we need to take care of it anyway - sb.WriteString(fmt.Sprintln(protocol + zone + ":" + addr)) + fmt.Fprintln(&sb, protocol+zone+":"+addr) continue } if ip == "" { - sb.WriteString(fmt.Sprintln(protocol + zone + ":" + port)) + fmt.Fprintln(&sb, protocol+zone+":"+port) continue } // if the server is listening on a specific address let's make it visible in the log, // so one can differentiate between all active listeners - sb.WriteString(fmt.Sprintln(protocol + zone + ":" + port + " on " + ip)) + fmt.Fprintln(&sb, protocol+zone+":"+port+" on "+ip) } return sb.String() } diff --git a/core/dnsserver/server_quic.go b/core/dnsserver/server_quic.go index d4561e770..a16375d44 100644 --- a/core/dnsserver/server_quic.go +++ b/core/dnsserver/server_quic.go @@ -368,7 +368,6 @@ func readDOQMessage(r io.Reader) ([]byte, error) { // A client or server receives a STREAM FIN before receiving all the bytes // for a message indicated in the 2-octet length field. // See https://www.rfc-editor.org/rfc/rfc9250#section-4.3.3-2.2 - //nolint:gosec if size != uint16(len(buf)) { // #nosec G115 -- buf length fits in uint16 return nil, fmt.Errorf("message size does not match 2-byte prefix") } diff --git a/plugin/auto/walk.go b/plugin/auto/walk.go index e1743e232..ade9914a4 100644 --- a/plugin/auto/walk.go +++ b/plugin/auto/walk.go @@ -39,7 +39,7 @@ func (a Auto) Walk() error { return nil } - reader, err := os.Open(filepath.Clean(path)) + reader, err := os.Open(filepath.Clean(path)) //nolint:gosec // G122: path is from filepath.Walk rooted in a.directory; symlinks must be followed for configmap-style mounts if err != nil { log.Warningf("Opening %s failed: %s", path, err) return nil diff --git a/plugin/cache/cache.go b/plugin/cache/cache.go index 3b59c9189..05223dec7 100644 --- a/plugin/cache/cache.go +++ b/plugin/cache/cache.go @@ -2,6 +2,7 @@ package cache import ( + "encoding/binary" "hash/fnv" "net" "time" @@ -110,8 +111,9 @@ func hash(qname string, qtype uint16, do, cd bool) uint64 { h.Write(zero) } - h.Write([]byte{byte(qtype >> 8)}) - h.Write([]byte{byte(qtype)}) + var qtypeBytes [2]byte + binary.BigEndian.PutUint16(qtypeBytes[:], qtype) + h.Write(qtypeBytes[:]) h.Write([]byte(qname)) return h.Sum64() } diff --git a/plugin/file/file.go b/plugin/file/file.go index 1d80c9520..bbbfe8279 100644 --- a/plugin/file/file.go +++ b/plugin/file/file.go @@ -156,7 +156,6 @@ func Parse(f io.Reader, origin, fileName string, serial int64) (*Zone, error) { // -1 is valid serial is we failed to load the file on startup. - //nolint:gosec if serial >= 0 && s.Serial == uint32(serial) { // #nosec G115 -- serial is validated non-negative, fits in uint32 return nil, &serialErr{err: "no change in SOA serial", origin: origin, zone: fileName, serial: serial} } diff --git a/plugin/k8s_external/transfer_test.go b/plugin/k8s_external/transfer_test.go index 934d58ac0..26642bb54 100644 --- a/plugin/k8s_external/transfer_test.go +++ b/plugin/k8s_external/transfer_test.go @@ -38,7 +38,7 @@ func TestTransferAXFR(t *testing.T) { if err != nil { t.Fatalf("Unexpected error: %v", err) } - var records []dns.RR //nolint:prealloc // records are read from a channel + var records []dns.RR for rrs := range ch { records = append(records, rrs...) } @@ -104,7 +104,7 @@ func TestTransferIXFR(t *testing.T) { if err != nil { t.Fatalf("Unexpected error: %v", err) } - var records []dns.RR //nolint:prealloc // records are read from a channel + var records []dns.RR for rrs := range ch { records = append(records, rrs...) } diff --git a/plugin/kubernetes/xfr_test.go b/plugin/kubernetes/xfr_test.go index 95e89b216..ebc876e33 100644 --- a/plugin/kubernetes/xfr_test.go +++ b/plugin/kubernetes/xfr_test.go @@ -88,7 +88,7 @@ func TestKubernetesIXFRCurrent(t *testing.T) { t.Error(err) } - var gotRRs []dns.RR //nolint:prealloc // records are read from a channel + var gotRRs []dns.RR for rrs := range ch { gotRRs = append(gotRRs, rrs...) } diff --git a/plugin/pkg/reuseport/listen_reuseport.go b/plugin/pkg/reuseport/listen_reuseport.go index 71fac3e76..4a25f2e4c 100644 --- a/plugin/pkg/reuseport/listen_reuseport.go +++ b/plugin/pkg/reuseport/listen_reuseport.go @@ -14,7 +14,13 @@ import ( func control(network, address string, c syscall.RawConn) error { c.Control(func(fd uintptr) { - if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil { + const maxInt = int(^uint(0) >> 1) + if fd > uintptr(maxInt) { + log.Warningf("Failed to set SO_REUSEPORT on socket: invalid file descriptor %d", fd) + return + } + + if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil { // #nosec G115 -- fd is range-checked above log.Warningf("Failed to set SO_REUSEPORT on socket: %s", err) } }) diff --git a/plugin/pkg/tls/tls.go b/plugin/pkg/tls/tls.go index a2a955f05..d469370c8 100644 --- a/plugin/pkg/tls/tls.go +++ b/plugin/pkg/tls/tls.go @@ -59,19 +59,29 @@ func setTLSDefaults(ctls *tls.Config) { func NewTLSConfigFromArgs(args ...string) (*tls.Config, error) { var err error var c *tls.Config + var certPath, keyPath, caPath string + if len(args) > 0 { + certPath = args[0] + } + if len(args) > 1 { + keyPath = args[1] + } + if len(args) > 2 { + caPath = args[2] + } switch len(args) { case 0: // No client cert, use system CA c, err = NewTLSClientConfig("") case 1: // No client cert, use specified CA - c, err = NewTLSClientConfig(args[0]) + c, err = NewTLSClientConfig(certPath) case 2: // Client cert, use system CA - c, err = NewTLSConfig(args[0], args[1], "") + c, err = NewTLSConfig(certPath, keyPath, "") case 3: // Client cert, use specified CA - c, err = NewTLSConfig(args[0], args[1], args[2]) + c, err = NewTLSConfig(certPath, keyPath, caPath) default: err = fmt.Errorf("maximum of three arguments allowed for TLS config, found %d", len(args)) } diff --git a/plugin/rewrite/name.go b/plugin/rewrite/name.go index ab4200352..f0c0e981f 100644 --- a/plugin/rewrite/name.go +++ b/plugin/rewrite/name.go @@ -161,10 +161,11 @@ func (rule *nameRuleBase) responseRuleFor(state request.Request) (ResponseRules, } rewriter := newRemapStringRewriter(state.Req.Question[0].Name, state.Name()) - rules := ResponseRules{ + rules := make(ResponseRules, 0, 2+len(rule.static)) + rules = append(rules, &nameRewriterResponseRule{rewriter}, &valueRewriterResponseRule{rewriter}, - } + ) return append(rules, rule.static...), RewriteDone } @@ -221,15 +222,16 @@ type suffixNameRule struct { } func newSuffixNameRule(nextAction string, auto bool, suffix, replacement string, answers ResponseRules) Rule { - var rules ResponseRules + rules := make(ResponseRules, 0, len(answers)) if auto { // for a suffix rewriter better standard response rewrites can be done // just by using the original suffix/replacement in the opposite order rewriter := newSuffixStringRewriter(replacement, suffix) - rules = ResponseRules{ + rules = make(ResponseRules, 0, 2+len(answers)) + rules = append(rules, &nameRewriterResponseRule{rewriter}, &valueRewriterResponseRule{rewriter}, - } + ) } return &suffixNameRule{ newNameRuleBase(nextAction, false, replacement, append(rules, answers...)), diff --git a/test/file_xfr_test.go b/test/file_xfr_test.go index 0ce331d79..391e80384 100644 --- a/test/file_xfr_test.go +++ b/test/file_xfr_test.go @@ -18,7 +18,7 @@ func TestLargeAXFR(t *testing.T) { sb.WriteString("example.com. IN SOA . . 1 60 60 60 60\n") sb.WriteString("example.com. IN NS ns.example.\n") for i := range numAAAAs { - sb.WriteString(fmt.Sprintf("%d.example.com. IN AAAA 2001:db8::1\n", i)) + fmt.Fprintf(&sb, "%d.example.com. IN AAAA 2001:db8::1\n", i) } // Setup the zone file and CoreDNS to serve the zone, allowing zone transfer