Runners are registered with the fritzlab label, not main. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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:
-
The
templateplugin cannot coexist withfilefor the same zone in a way that lets file records take priority. See this upstream discussion. Thesyntheticplugin is designed to work alongsidefile, deferring to it for static records. -
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 ./...