Forwarding concepts
DNS-name Targets
A rule target may be a hostname instead of an IP literal. Cached, single-flighted, RFC-8767 stale-while-error.
How to set it up: Standalone (TOML) · Server + Client (operator)
Available since v0.3.0. The target host in any push-rule may be a DNS
name (e.g. api.example.com:443) instead of an IP literal.
How it works
- Resolution happens lazily on first connect through
hickory-resolverreading/etc/resolv.conf. - Results cache per the resolver-reported TTL clamped to
[5 s, 5 min]. The cache is bounded (default 8192 entries) so high name-cardinality workloads can't grow it without limit; expired entries are evicted first, then the live entries closest to expiry if still over the cap. - On refresh failure the rule stays
Activeand the last-known answer continues serving for 30 s of grace (RFC 8767 stale-while-error). After grace expiry, a fresh attempt is allowed every 3 s. - Per-rule single-flight collapses concurrent first-connects to ONE upstream resolver call.
- Multi-A/AAAA fallback tries each returned address in family-preference order — a single dead IP doesn't fail the connection.
- IPv4-first by default; pass
--prefer-ipv6to flip per rule.
Hot path
IP-literal targets skip the resolver entirely: IpAddr::from_str
short-circuits straight to the dial. The dial itself is time-boxed
by the per-attempt timeout (3 s), so a SYN-blackhole target (a firewall
that drops rather than refuses) fails fast instead of wedging a task in
kernel SYN-retransmit for ~75–127 s.
DNS-target hot path performance:
- Cache-hit lookup: ~75 ns median (one async-mutex acquire + HashMap get + Vec clone).
- 100 concurrent first-connects to the same hostname: resolver invoked exactly once.