Skip to content

v1.6.7

Choose a tag to compare

@semihalev semihalev released this 18 May 13:36
· 130 commits to main since this release

A feature release: DNS64 (RFC 6147) lands as a first-class middleware, and the private-package layout gets tightened with an internal/ move. No security fixes in this one.

What's Changed

Features

  • DNS64 middleware (RFC 6147, #472). New middleware/dns64 synthesises AAAA records from A records for IPv6-only clients reaching IPv4-only services. Sits between kubernetes and cache; activates when a client's AAAA query has no usable answer and a secondary A lookup succeeds, embedding each IPv4 into a configured Pref64::/n per RFC 6052 §2.2.

    RFC 6147 coverage at a glance:

    • §5.1.2 / §5.1.3 RCODE handling — NOERROR-NODATA / non-NXDOMAIN errors trigger synthesis; NXDOMAIN passes through.
    • §5.1.4 exclusions — default AAAA exclusion ::ffff:0:0/96; default A exclusion under WKP follows the IANA Special-Purpose registry (incl. 192.88.99.0/24 per RFC 7526).
    • §5.1.5 CNAME / DNAME chains preserved on both synthesis and the no-A-records path.
    • §5.1.6 — when the AAAA query yields empty/error, the A response's RCODE, Authority section, and chain become the basis for the client reply.
    • §5.1.7 TTL = min(A TTL, AAAA negative-cache TTL); 600 s ceiling when no SOA is present.
    • §5.2 multiple Pref64 prefixes synthesise in parallel; the well-known prefix 64:ff9b::/96 is the runtime default when none is configured.
    • §5.3.1 PTR translation via CNAME to in-addr.arpa with optional best-effort chase.
    • §5.3.2 — only Answer-section AAAAs are synthesised; Authority/Additional pass through unmodified.
    • §5.5 DNSSEC safetyCD=1 requests and SERVFAILs carrying DNSSEC-validation EDE codes (1, 2, 5–12, 27) bypass synthesis entirely; on synthesised replies, AD is cleared and EDE 4 (Forged Answer) is attached when the upstream had AD=1.
    • RD=0 clients skip DNS64 entirely.

    Configuration:

    [dns64]
    enabled = true
    prefixes = [\"64:ff9b::/96\"]
    client_networks = []                          # empty = all clients
    exclude_zones = []
    exclude_aaaa_networks = [\"::ffff:0:0/96\"]
    exclude_a_networks = [...]                    # IANA Special-Purpose default

    Metrics: `dns64_synthesised_total`, `dns64_ptr_translated_total`, `dns64_passthrough_total{reason}`, `dns64_a_lookup_failures_total{reason}`.

    Closes the last open item on the README TODO list.

Internal Refactor (#479)

Five packages that were never intended as public API move under `internal/`:

Old path New path
`cache` `internal/cache`
`util` `internal/dnsutil` (renamed)
`waitgroup` `internal/waitgroup`
`mock` `internal/mock`
`authority` `internal/authority`

`util` is renamed to `dnsutil` at the same time — the old name was the lowest-information identifier in Go and the package's actual contents (EDE, TTL, RRset construction, response classification) are entirely DNS-message helpers. The new name is self-documenting.

Pure rename + import-path updates, no behavioural changes. The module path is unchanged so the public binary and middleware-extension API (`middleware.Constructor` / `*config.Config`) keep working. External plugin authors who imported any of the five packages directly will need to either pin to an older version, vendor, or remove the dependency.

API Documentation

`api/README.md` rewritten end-to-end (139 → 105 lines). Fixes several inaccuracies in the previous draft:

  • `/api/v1/block/exists/:key` returns `{"exists": }`, not the previously documented `{"success": true}`.
  • `/api/v1/block/set/:key` and `/api/v1/block/remove/:key` can return `success: false` on duplicate / missing — not always `true`.
  • 404 response shape for `/api/v1/block/get/:key` and 401 response shape are now documented explicitly.
  • Bulk batch 400 cases (malformed JSON, unknown fields, oversized body, empty keys) documented.
  • `/debug/pprof/*` routes documented with their auth-bypass caveat.
  • `ReadHeaderTimeout`, `MaxBytesReader`, graceful-shutdown timeout, and async blocklist persistence semantics documented.

Conversational style with an endpoint table up top for quick scan and curl examples interleaved with prose where they help.

Dependencies

  • `k8s.io/client-go`, `k8s.io/apimachinery` → v0.36.1 (#476, #477)
  • `github.com/quic-go/quic-go` → v0.59.1 (#475)
  • `golang.org/x/sys` → v0.44.0 (#474)
  • `github.com/fsnotify/fsnotify` → v1.10.1 (#468)

Upgrade Notes

  • DNS64 is opt-in. `enabled = false` by default; existing deployments behave identically to 1.6.6 until you flip it.

  • Config compatibility: `configver` bumps to `1.6.7`. Existing configs continue to parse — you'll see a one-line "Config file is out of version" log warning until you regenerate. `contrib/linux/sdns.conf` has been refreshed and is the easiest reference for the new `[dns64]` block.

  • Plugin authors who imported moved packages need to update import paths. Migration cheat-sheet:

    github.com/semihalev/sdns/cache       → github.com/semihalev/sdns/internal/cache
    github.com/semihalev/sdns/util        → github.com/semihalev/sdns/internal/dnsutil   # also rename util.X → dnsutil.X
    github.com/semihalev/sdns/waitgroup   → github.com/semihalev/sdns/internal/waitgroup
    github.com/semihalev/sdns/mock        → github.com/semihalev/sdns/internal/mock
    github.com/semihalev/sdns/authority   → github.com/semihalev/sdns/internal/authority
    

    Since these are now `internal/`, the Go compiler will refuse to compile any out-of-tree code that imports them. The intended path forward for plugin authors is to depend only on the public middleware-extension surface (`config`, `middleware`, `ctx`, `server`).

  • No on-disk format changes to `trust-anchor.db` / `trust-anchor-tombstones.db` / blocklist persistence.

Full Changelog: v1.6.6...v1.6.7