The DNS Gateway implements an Application Level Gateway (ALG) that translates real IP addresses to synthetic "fake" IP addresses, maintaining bidirectional mappings between domains, real IPs, and fake IPs. This translation layer enables DNS-based routing policies, per-app split tunneling, and integration with blocklists and DNS64/NAT64.
For DNS transport implementations (DoH, DoT, DNS53, etc.), see 2.2 For DNS caching strategies including transport-level caching and request coalescing, see 2.3 For IP address management and the IPMap system that consumes ALG translations, see 2.4
The ALG system serves three primary functions:
alg, nat, ptr) to translate between domains, fake IPs, and real IPs.The Gateway interface intra/dnsx/alg.go92-113 defines the public API for ALG operations:
Title: Gateway Interface and Internal Methods
Sources: intra/dnsx/alg.go92-113 intra/dnsx/alg.go1864 intra/dnsx/alg.go1974 intra/dnsx/alg.go1996 intra/dnsx/alg.go1514
The ALG system maintains three synchronized maps for bidirectional translation within the dnsgateway struct intra/dnsx/alg.go857-877:
Title: ALG Mapping Architecture
Map Details:
| Map | Key | Value | Purpose |
|---|---|---|---|
alg | domain+":a:"+idx or domain+":aaaa:"+idx | *algans | Forward lookup: domain → fake IP intra/dnsx/alg.go858 |
nat | algip (netip.Addr) | *baseans | Undo ALG: fake IP → real IPs intra/dnsx/alg.go860 |
ptr | realip (netip.Addr) | *baseans | Reverse: real IP → domains intra/dnsx/alg.go862 |
Sources: intra/dnsx/alg.go857-877 intra/dnsx/alg.go1514-1603
Title: ALG Data Entities and Relationships
Key Structures:
algans intra/dnsx/alg.go798-808: Associates a fake ALG IP with a baseans.baseans intra/dnsx/alg.go773-786: Contains all answer data including real IPs, domains, and blocklists.xips intra/dnsx/alg.go210-221: Tracks primary and secondary (aux) IP answers with TTL tracking.expaddr intra/dnsx/alg.go132-136: IP addresses with expiry time and date of birth for freshness tracking.xdomains intra/dnsx/alg.go620-624: Domain names with expiry tracking per transport+UID.Sources: intra/dnsx/alg.go773-849 intra/dnsx/alg.go210-265 intra/dnsx/alg.go132-184 intra/dnsx/alg.go620-771
The system supports two IP generation strategies:
Default mode that increments IP octets/hexes sequentially intra/dnsx/alg.go1605-1678:
IPv4 (100.64.0.0/10):
100.64.0.1 intra/dnsx/alg.go71octets[3] up to 254.octets[2] and reset octets[3].octets[1] up to 128.alg map intra/dnsx/alg.go1663-1676IPv6 (64:ff9b:1:da19::/96):
64:ff9b:1:da19:100:0:0:0 intra/dnsx/alg.go72hexes[7] up to 65534.hexes[6] and reset hexes[7].hexes[5] and reset hexes[6], hexes[7].Sources: intra/dnsx/alg.go1605-1678 intra/dnsx/alg.go1696-1753 intra/dnsx/alg.go71-72
When chash=true, generates deterministic IPs using FNV hash intra/dnsx/alg.go1624-1635:
Title: Consistent Hashing IP Generation
Functions:
gen4Locked() intra/dnsx/alg.go1681-1694: Generates IPv4 using 22-bit hash.gen6Locked() intra/dnsx/alg.go1756-1776: Generates IPv6 using 48-bit hash.hash22() and hash48() use fnv.New32a() and fnv.New64a() hashing intra/dnsx/alg.go14Sources: intra/dnsx/alg.go1624-1635 intra/dnsx/alg.go1715-1723 intra/dnsx/alg.go1681-1694 intra/dnsx/alg.go1756-1776
Title: DNS Query Sequence with ALG
Key Steps:
xips already has answer for domain+tid+uid.t1, potentially from cache.t2 for blocklists.NatPt.D64.mod flag.Sources: intra/dnsx/alg.go1142-1458 intra/dnsx/alg.go1514-1603 intra/dnsx/x64.go37
The X() method intra/dnsx/alg.go1801-1811 reverses ALG translation, converting fake IPs back to real IPs:
Title: IP Translation Reversal Logic (X)
Logic:
UidSelf or transport skips cache, don't translate intra/dnsx/alg.go1877-1881nat map (fake → real) intra/dnsx/alg.go1887-1895ptr map (real → real) intra/dnsx/alg.go1896-1910NatPt.X64() intra/dnsx/x64.go45undidAlg/undidPtr is true, return empty (signals stale cache) intra/dnsx/alg.go1940maybeAlg as-is (not an ALG IP).Sources: intra/dnsx/alg.go1801-1946 intra/dnsx/alg.go1864-1946 intra/dnsx/alg.go1948-1972 intra/dnsx/x64.go45
The PTR() method intra/dnsx/alg.go1813-1829 retrieves domain names associated with an IP:
Method Signature: PTR(maybeAlg netip.Addr, uid, tid string, force bool) (domaincsv string, didForce bool)
Lookup Strategy:
| Condition | Map Used | Notes |
|---|---|---|
mod=true && !force | nat map | Prefer fake IP → domains via nat intra/dnsx/alg.go1976 |
| `mod=false | force` |
Sources: intra/dnsx/alg.go1813-1829 intra/dnsx/alg.go1974-1994
The RESOLV() method intra/dnsx/alg.go1831-1855 retrieves IPs associated with a domain:
Title: Forward Domain Resolution Logic (RESOLV)
Query Types:
| Type | Returns | Source |
|---|---|---|
typalg | Fake ALG IPs from alg map | intra/dnsx/alg.go2013-2045 |
typreal | Real IPs from alg[].ips.realipsFor() | intra/dnsx/alg.go2046-2061 |
typsecondary | Secondary IPs from alg[].ips.secipsFor() | intra/dnsx/alg.go2062-2075 |
Sources: intra/dnsx/alg.go1831-1855 intra/dnsx/alg.go1996-2077
The xips structure intra/dnsx/alg.go210-221 tracks IP addresses with expiry times:
Title: IP Address Freshness Tracking
Key Methods:
fresh() intra/dnsx/alg.go158-165: Returns remaining TTL and freshness boolean.get(xaddrstatus) intra/dnsx/alg.go186-198: Returns IPs if alive (xalive) or all (xall).realips(uid, xaddrstatus) intra/dnsx/alg.go322-344: Gets primary IPs, checks for block via secondary.TTL Constants:
| Constant | Value | Purpose |
|---|---|---|
ttl2m | 2 minutes | Max TTL for ALG/NAT IP mapping intra/dnsx/alg.go38 |
ttl8s | 8 seconds | Min TTL for ALG/NAT IP mapping intra/dnsx/alg.go39 |
ttl3s | 3 seconds | Timeout for DNS64 undo operations intra/dnsx/alg.go42 |
Sources: intra/dnsx/alg.go35-50 intra/dnsx/alg.go132-184 intra/dnsx/alg.go322-399
Split tunneling allows different apps (UIDs) to use different DNS transports and have separate blocklist decisions.
Title: Split Tunneling Configuration State
Flags:
mod intra/dnsx/alg.go874: When true, enables ALG translation (real IPs → fake IPs).split intra/dnsx/alg.go876: When true, maintains separate caches per UID.fix intra/dnsx/alg.go875: When true, enforces dnsx.Fixed transport usage.Sources: intra/dnsx/alg.go874-876 intra/dnsx/alg.go904-922 intra/dnsx/alg.go1805-1807 intra/dnsx/alg.go1817-1819 intra/dnsx/alg.go1839-1841
The ALG system integrates with the NatPt interface intra/dnsx/x64.go22-25 for DNS64/NAT64 support:
Title: NAT-PT Integration with ALG
DNS64 Flow (D64):
dns64.eval().DNSSummary.NAT64 Undo (X64):
ip6to4 intra/x64/nat64.go36-59Sources: intra/dnsx/alg.go1245-1260 intra/dnsx/alg.go1948-1972 intra/x64/natpt.go67-126 intra/x64/dns64.go163-230 intra/x64/nat64.go31-59
The ALG system provides an internal cache separate from transport-level caching:
Title: Internal ALG Cache Retrieval (fromInternalCache)
Sources: intra/dnsx/alg.go972-1012 intra/dnsx/alg.go1996-2077
When a transport is stopped, the gateway invalidates its cached entries:
Method: onStopped(tid string) intra/dnsx/alg.go924-958
Title: Cache Invalidation on Transport Stop
Sources: intra/dnsx/alg.go924-958 intra/dnsx/alg.go400-434 intra/dnsx/alg.go698-722
The resolver creates and manages the gateway:
Title: Resolver and Gateway Orchestration
Sources: intra/dnsx/transport.go197-233 intra/dnsx/alg.go882-902
| Function | Purpose | Location |
|---|---|---|
NewDNSGateway() | Construct gateway with fake addrs, rdns, dns64 | intra/dnsx/alg.go882-902 |
q() | Query transports with ALG translation | intra/dnsx/alg.go1088 |
X() | Undo ALG, translate fake → real IPs | intra/dnsx/alg.go1801-1811 |
PTR() | Reverse lookup IP → domains | intra/dnsx/alg.go1813-1829 |
RESOLV() | Forward lookup domain → IPs | intra/dnsx/alg.go1831-1855 |
registerLocked() | Register alg/nat/ptr mappings | intra/dnsx/alg.go1514-1603 |
take4Locked() | Generate or retrieve IPv4 ALG IP | intra/dnsx/alg.go1605-1678 |
take6Locked() | Generate or retrieve IPv6 ALG IP | intra/dnsx/alg.go1696-1753 |
fromInternalCache() | Answer from internal cache | intra/dnsx/alg.go972-1012 |
onStopped() | Invalidate transport cache | intra/dnsx/alg.go924-958 |
Sources: intra/dnsx/alg.go882-2077
Refresh this wiki