Donavan Fritz 85d9adbbed
All checks were successful
Synthetic CoreDNS Plugin CI/CD Build / test (push) Successful in 1m50s
Fix CI runner label: main -> fritzlab
Runners are registered with the fritzlab label, not main.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 13:35:18 -05:00
2024-02-08 17:44:51 -08:00
2024-02-08 17:44:51 -08:00

synthetic

A CoreDNS plugin that generates DNS records from IP addresses embedded in hostnames.

Inspired by dnsmasq's synth-domain option, synthetic provides automatic alignment between forward and reverse lookups — eliminating a common class of DNS misconfigurations described in RFC 1912 Section 2.1.

Features

  • Forward lookups (A/AAAA) — extract an IP from a prefixed hostname and respond directly
  • Reverse lookups (PTR) — generate a synthetic hostname from a reverse query
  • Static record priority — responses from upstream plugins (e.g., file) always take precedence over synthetic records
  • Dual-stack — full IPv4 and IPv6 support, including compressed IPv6 notation
  • Configurable — custom prefix, TTL, and per-network scoping

How It Works

Forward Lookups (A / AAAA)

A hostname with an embedded IP address is resolved directly. Dots (IPv4) or colons (IPv6) are replaced with dashes in the hostname label:

Hostname Record Address
ip-192-0-2-1.example.com A 192.0.2.1
ip-2001-db8-abcd--1.example.com AAAA 2001:db8:abcd::1
ip-2001-0db8-0000-0000-0000-0000-0000-0001.example.com AAAA 2001:db8::1

Only addresses within a configured net CIDR are resolved. All other queries pass through to the next plugin.

Reverse Lookups (PTR)

When a PTR query arrives, the plugin first consults the next plugin in the chain. If that plugin provides a successful answer (e.g., from a zone file), it is used as-is. Otherwise, a synthetic PTR record is generated pointing back to the corresponding forward hostname.

IPv6 reverse responses use the compressed address form per RFC 5952.

Configuration

Directives

Directive Description Default
net CIDR network(s) for which synthetic forward responses are generated. May be specified multiple times. (none — required for forward lookups)
forward Domain name appended to synthetic hostnames in PTR responses. (none — required for reverse lookups)
ttl Time-to-live for synthetic responses, in seconds. 0
prefix Hostname label prefix identifying synthetic queries. A trailing dash is added automatically. ip

Examples

Forward lookups for two IPv6 prefixes and one IPv4 prefix:

example.com {
    synthetic {
        net 2001:db8:abcd::/48
        net 2001:db8:1234::/48
        net 192.0.2.0/24
        prefix ip
        ttl 300
    }
    file db.example.com
}

Reverse lookups for an IPv6 prefix, with zone file records taking priority:

d.c.b.a.8.b.d.0.1.0.0.2.ip6.arpa {
    synthetic {
        forward example.com
        prefix ip
    }
    file d.c.b.a.8.b.d.0.1.0.0.2.ip6.arpa
}

Compiling into CoreDNS

Follow the standard external plugin procedure. Add the following line to plugin.cfg in the CoreDNS source tree:

synthetic:code.fritzlab.net/dns/synthetic

Then rebuild CoreDNS:

go generate
go build

FAQ

Why not use the template plugin?

Two reasons:

  1. The template plugin cannot coexist with file for the same zone in a way that lets file records take priority. See this upstream discussion. The synthetic plugin is designed to work alongside file, deferring to it for static records.

  2. Writing regex patterns to match arbitrary IPv4 and IPv6 addresses within CIDR ranges is impractical. This plugin accepts CIDR notation directly.

Development

# Run tests
go test -v ./...

# Lint
go vet ./...

License

Apache License 2.0

Description
No description provided
Readme Apache-2.0 78 KiB
Languages
Go 99%
Dockerfile 1%