Apps/Dns64App/README.md
A DNS App for Technitium DNS Server that implements RFC 6147 DNS64 functionality to enable IPv6-only clients to access IPv4-only resources through DNS protocol translation.
This app extends the Technitium DNS Server to synthesize AAAA records from A records, allowing IPv6-only clients to discover and access IPv4 resources when used in conjunction with a NAT64 gateway. The app operates as both a post-processor for recursive queries and an authoritative request handler for reverse DNS lookups within the DNS64 address space.
DNS64 App implements DNS Extensions for Network Address Translation from IPv6 Clients to IPv4 Servers as defined in RFC 6147. The app enables seamless connectivity for IPv6-only networks by translating IPv4 addresses into synthesized IPv6 addresses using configurable prefix mappings.
Key capabilities include:
This app provides critical infrastructure support for dual-stack migration strategies and IPv6-only network deployments.
DNS64 must be deployed in conjunction with a functional NAT64 gateway. The app performs DNS protocol translation only—it does not provide network address translation.
Operational Risk:
Installing and enabling DNS64 App without a corresponding NAT64 gateway in place will cause connectivity failures for IPv6-only clients attempting to reach IPv4-only destinations. Synthesized AAAA records will resolve to IPv6 addresses that cannot be routed without NAT64.
Deployment Options:
enableDns64: false initially, deploy NAT64, then enable DNS64Processing Order:
DNS64 operates as a post-processor in the DNS resolution pipeline. It processes responses after recursive resolution and before returning results to clients.
Open the Technitium DNS Server web console
Navigate to Apps section
Click App Store and find the DNS64 App to install
Configure the app by clicking on the Config button
The DNS64 App is configured through the dnsApp.config JSON file. The configuration defines global settings, network-to-group mappings, and per-group DNS64 policies.
All configuration options are documented below. The structure supports hierarchical policy enforcement based on client network origin.
| Property | Type | Default | Description |
|---|---|---|---|
appPreference | integer | 30 | Processing priority when multiple apps implement IDnsApplicationPreference. Lower values execute first. |
enableDns64 | boolean | (required) | Global DNS64 enable flag. When false, app is inactive regardless of group settings. |
networkGroupMap | object | (required) | Maps client network addresses (CIDR notation) to named groups. Longest prefix match determines group assignment. |
groups | array | (required) | Array of group objects defining DNS64 policies. Groups are referenced by name from networkGroupMap. |
The networkGroupMap object maps client source networks to named policy groups using CIDR notation as keys and group names as values.
Purpose:
Enables differentiated DNS64 behavior based on client network origin. Supports granular policy enforcement for internal vs. external clients, different VLANs, or trust zones.
Matching Logic:
The app performs longest prefix match. If a client IP matches multiple networks, the most specific (longest prefix length) mapping is selected.
JSON Example:
"networkGroupMap": {
"::/0": "default-group",
"2001:db8:1000::/48": "internal-group",
"2001:db8:2000::/48": "guest-group"
}
Each group object defines a complete DNS64 policy.
| Property | Type | Default | Description |
|---|---|---|---|
name | string | (required) | Unique identifier for the group. Referenced by networkGroupMap. |
enableDns64 | boolean | (required) | Group-level DNS64 enable flag. Allows per-group activation/deactivation. |
dns64PrefixMap | object | (required) | Maps IPv4 network ranges to DNS64 IPv6 prefixes. Keys are IPv4 CIDR, values are IPv6 prefix strings or null. |
excludedIpv6 | array | [] | Array of IPv6 network addresses (CIDR) to exclude from DNS64 processing. Existing AAAA records in these ranges suppress synthesis. |
The dns64PrefixMap object within each group defines how IPv4 addresses are translated into IPv6 addresses.
Structure:
Keys are IPv4 network addresses in CIDR notation. Values are either:
null to exclude the IPv4 range from DNS64 processingPrefix Length Constraints:
DNS64 prefixes must use one of the following RFC 6147-compliant prefix lengths: 32, 40, 48, 56, 64, or 96.
Matching Logic:
Longest prefix match. The most specific IPv4 network match determines the DNS64 prefix used for synthesis.
JSON Example:
"dns64PrefixMap": {
"0.0.0.0/0": "64:ff9b::/96",
"10.0.0.0/8": null,
"172.16.0.0/12": null,
"192.168.0.0/16": null,
"203.0.113.0/24": "2001:db8:64::/96"
}
Explanation:
64:ff9b::/96 prefix (well-known prefix from RFC 6052)2001:db8:64::/96The excludedIpv6 array prevents DNS64 synthesis when existing AAAA records fall within specified IPv6 ranges.
Purpose:
Prevents synthesis when legitimate IPv6 addresses already exist but should not be used (e.g., IPv4-mapped IPv6 addresses).
Common Exclusions:
::ffff:0:0/96 — IPv4-mapped IPv6 addresses (RFC 4291 Section 2.5.5.2)JSON Example:
"excludedIpv6": [
"::ffff:0:0/96",
"2001:db8:exclude::/48"
]
{
"appPreference": 30,
"enableDns64": true,
"networkGroupMap": {
"::/0": "everyone",
"2001:db8:internal::/48": "internal-ipv6"
},
"groups": [
{
"name": "everyone",
"enableDns64": true,
"dns64PrefixMap": {
"0.0.0.0/0": "64:ff9b::/96",
"10.0.0.0/8": null,
"172.16.0.0/12": null,
"192.168.0.0/16": null
},
"excludedIpv6": [
"::ffff:0:0/96"
]
},
{
"name": "internal-ipv6",
"enableDns64": true,
"dns64PrefixMap": {
"0.0.0.0/0": "2001:db8:64::/96",
"10.0.0.0/8": "2001:db8:64:a::/96",
"172.16.0.0/12": "2001:db8:64:ac::/96",
"192.168.0.0/16": "2001:db8:64:c0::/96"
},
"excludedIpv6": [
"::ffff:0:0/96"
]
}
]
}
The app supports standard RFC 6147 prefix lengths. The IPv4 address is embedded within the IPv6 prefix according to the prefix length.
Supported Prefix Lengths:
| Prefix Length | Format | IPv4 Embedding |
|---|---|---|
/32 | pppp:pppp::/32 | Bits 32-63 and 64-95 |
/40 | pppp:pppp:pp00::/40 | Bits 40-63 and 64-95 |
/48 | pppp:pppp:pppp::/48 | Bits 48-63 and 64-95 |
/56 | pppp:pppp:pppp:pp00::/56 | Bits 56-63 and 64-95 |
/64 | pppp:pppp:pppp:pppp::/64 | Bits 64-95 |
/96 | pppp:pppp:pppp:pppp:pppp:pppp::/96 | Bits 96-127 |
Well-Known Prefix:
RFC 6052 defines 64:ff9b::/96 as the well-known prefix for DNS64/NAT64 deployments.
Example:
IPv4 address 192.0.2.1 with prefix 64:ff9b::/96 becomes 64:ff9b::192.0.2.1 or 64:ff9b::c000:201.
The DNS64 App implements two distinct processing paths:
networkGroupMap using longest prefix matchexcludedIpv6 ranges, no synthesis occursdns64PrefixMap using longest prefix match.ip6.arpa domainnetworkGroupMapdns64PrefixMap values.in-addr.arpa domainSymptoms: IPv6-only clients receive no AAAA records for domains that should trigger DNS64 synthesis.
Diagnostic Steps:
enableDns64: true at both root and group levelnetworkGroupMapdns64PrefixMap: null mappingexcludedIpv6 rangesConfiguration Check:
Review dns64PrefixMap for correct CIDR notation and prefix lengths (32, 40, 48, 56, 64, 96 only).
Logs:
Enable DNS server query logging to observe DNS64 post-processing behavior and internal A record queries.
Symptoms: Clients receive AAAA records but connections fail or time out.
Diagnostic Steps:
dns64PrefixMap prefixesping6 64:ff9b::8.8.8.8Common Cause:
DNS64 deployed without corresponding NAT64 infrastructure.
Symptoms: RFC 1918 private addresses (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) are converted to IPv6.
Resolution:
Add exclusions to dns64PrefixMap:
"dns64PrefixMap": {
"10.0.0.0/8": null,
"172.16.0.0/12": null,
"192.168.0.0/16": null
}
Private IPv4 addresses should generally not be translated unless dual-stack NAT64 is explicitly configured.
Symptoms: PTR queries for synthesized IPv6 addresses return NXDOMAIN.
Diagnostic Steps:
.in-addr.arpa) exists and is resolvable.ip6.arpa to .in-addr.arpaExpected Behavior:
App returns authoritative CNAME from .ip6.arpa to .in-addr.arpa, then server recursively resolves PTR.
Symptoms: Configuration validation fails with "DNS64 prefix can have only the following prefixes" error.
Resolution:
Verify all DNS64 prefix values in dns64PrefixMap use only permitted prefix lengths: /32, /40, /48, /56, /64, or /96.
Invalid Example:
"dns64PrefixMap": {
"0.0.0.0/0": "2001:db8::/80" // Invalid - /80 is not one of the supported prefix lengths
}
Corrected Example:
"dns64PrefixMap": {
"0.0.0.0/0": "2001:db8:64::/96"
}