mxcheck 2.0.1 retries DNS lookups that time out and installs as a Go v2 module

3 hours ago

mxcheck checks e-mail servers for DNS and configuration errors. This run looks up the A, PTR and SPF records, and each one is a DNS query. Version 2.0.1 retries those lookups when a query times out. It also fixes the Go module path so Go can install the 2.0 line, and updates dependencies for security fixes.

Ask about this presentation

Chapters

  1. 0:00mxcheck 2.0.1
  2. 0:24Timed-out queries
  3. 0:43exchangeWithRetry
  4. 1:06Every record check
  5. 1:29The /v2 module path
  6. 1:54Security updates
  7. 2:18What could break
  8. 2:41Upgrade
Show transcript
  1. mxcheck checks e-mail servers for DNS and configuration errors. This run looks up the A, PTR and SPF records, and each one is a DNS query. Version 2.0.1 retries those lookups when a query times out. It also fixes the Go module path so Go can install the 2.0 line, and updates dependencies for security fixes.

    Slide text
    mxcheck

    mxcheck 2.0.1 retries DNS lookups that time out

    It also installs as a Go module at …/mxcheck/v2, with security-updated dependencies.

    mxcheck output: checking for the A record, the PTR record and the SPF record
  2. Up to 2.0.0, mxcheck sent each DNS question once. If a single UDP packet got lost, or the upstream resolver was slow, that query timed out and the whole lookup failed, which made lookups flaky. Now a query that times out is sent again, and a later attempt can still get the answer.

    Slide text
    DNS retry /v2 path Security Upgrade

    One timed-out query used to fail the whole lookup

    2.0.0
    query
    →
    timeout
    →
    lookup fails
    2.0.1
    query
    →
    timeout
    →
    query again
    →
    answer
  3. The fix is one new helper in dns.go, called exchangeWithRetry. It allows three attempts in total. Each attempt is the same exchange call mxcheck made before. The loop stops as soon as there is an answer, or as soon as the error is anything other than a timeout. So every other error comes back right away, exactly as it did in 2.0.0.

    Slide text
    DNS retry /v2 path Security Upgrade

    Three attempts, and only timeouts are retried

    const dnsRetries = 3
    
    func exchangeWithRetry(c *dns.Client, m *dns.Msg, addr string) (…) {
    	// …
    	for i := 0; i < dnsRetries; i++ {
    		in, rtt, err = c.Exchange(m, addr)
    		var netErr net.Error
    		if err == nil || !errors.As(err, &netErr) || !netErr.Timeout() {
    			break
    		}
    	}
    	return in, rtt, err
    }

    dns.go

  4. The helper replaces the direct exchange call in every record lookup in dns.go, from MX and SPF to DKIM, DMARC, DANE and BIMI, plus the blacklist check. A new test runs a local DNS server that drops queries on purpose. It checks an answer on the first try, an answer after one timeout, and every attempt timing out, with no network needed.

    Slide text
    DNS retry /v2 path Security Upgrade

    Every DNS record check now goes through the retry

    MX A PTR SPF MTA-STS DKIM DMARC TLSRPT DANE BIMI blacklists
    Test_exchangeWithRetry · local DNS server, no network
    • answer on first try
    • answer after one timeout
    • all attempts time out
  5. Go expects a module at version 2 or higher to end its path in slash v2. The 2.0.0 release kept the old path, so Go's module tooling couldn't fetch it, and the package page on pkg.go.dev still listed 1.8.0. Version 2.0.1 declares the module as mxcheck slash v2, and the Go Reference badge in the README now points to that path.

    Slide text
    DNS retry /v2 path Security Upgrade

    Go can now fetch the 2.0 line

    go.mod in 2.0.0
    module github.com/steffenfritz/mxcheck
    go.mod in 2.0.1
    module github.com/steffenfritz/mxcheck/v2

    The Go Reference badge in the README now points to pkg.go.dev/github.com/steffenfritz/mxcheck/v2.

  6. The security work in this release is all in dependencies and the toolchain. The x/sys update fixes a vulnerability listed in Go's vulnerability database, and x/net and x/mod move up for security fixes as well. The release packages are now built with Go 1.27 instead of Go 1.25, which no longer receives security fixes.

    Slide text
    DNS retry /v2 path Security Upgrade

    Security fixes come from dependencies and the Go toolchain

    golang.org/x/sysv0.42.0→v0.48.0fixes GO-2026-5024
    golang.org/x/netv0.52.0→v0.60.0security fixes
    golang.org/x/modv0.34.0→v0.40.0security fixes
    Go 1.25 → Go 1.27
    builds the release packages and runs CI
  7. The go directive in go.mod moved from 1.25 to 1.26, so building or installing mxcheck from source now needs Go 1.26 or newer. A DNS server that doesn't answer at all now gets three tries, so mxcheck takes up to three timeouts to give up on it. The command-line flags are the same as in 2.0.0.

    Slide text
    DNS retry /v2 path Security Upgrade

    Building from source now needs Go 1.26 or newer

    The go.mod directive moved from 1.25.0 to 1.26.0
    The pre-built packages are unaffected.
    A DNS server that never answers costs three timeouts
    mxcheck takes longer to report a dead resolver set with -d.
    Command-line flags are unchanged
    This release touches no flag definitions.
  8. This is a maintenance release, and it adds no new checks. With Go, run go install on the module path that ends in slash v2, at version 2.0.1. The release page also carries Debian packages for amd64 and arm64 and a macOS arm64 tarball, each with a signature file. mxcheck 2.0.1 retries DNS lookups that time out.

    Slide text
    DNS retry /v2 path Security Upgrade

    Upgrade to 2.0.1 from the /v2 module path

    go install github.com/steffenfritz/mxcheck/v2 @v2.0.1
    .deb amd64 · arm64
    macOS arm64 tarball
    signed with .asc files

    github.com/steffenfritz/mxcheck/releases/tag/v2.0.1

What happened in AI today, in your inbox

One short email each evening. Read it and you’re caught up.

Built in New York with ❤️