Architecture and Design
This page expands on the architectural background that is only summarized in the README. The focus is the request path, the plugin layering model, and the performance constraints behind the design.
Core Request Path
ForgeDNS is organized around this path:
server -> DnsContext -> matcher / executor / provider -> upstream or side effects -> response
server- Accepts UDP, TCP, DoT, DoQ, and DoH traffic.
DnsContext- Carries the query, response, metadata, and policy state for one request.
matcher- Evaluates branch conditions.
executor- Performs forwarding, cache access, fallback, rewrites, local answers, and integrations.
provider- Supplies reusable domain/IP datasets.
Why This Layering
ForgeDNS avoids scattering policy logic across listeners or transports. It centralizes decision making in the policy layer for several reasons:
- The hot path is shorter and easier to optimize.
- Features compose naturally across protocols.
- New capabilities fit better as plugins than as transport-specific special cases.
- Configuration remains stable and predictable as policy complexity grows.
Design Priorities
1. Performance Before Feature Accumulation
The target is not to pile up switches. The target is to keep complex policies operationally predictable.
- Keep the hot path short.
- Avoid repeating work per request.
- Reuse upstream connections and transport state.
- Move observability and side effects away from the most latency-sensitive path.
2. Policy as a First-Class Capability
ForgeDNS is not just a forwarder. It is a composable policy engine.
sequenceorders execution.matcherdetermines branch conditions.executorperforms actions.providershares datasets.
This is easier to evolve than embedding rule logic into listeners or upstream modules.
3. System Integration Is Part of the Architecture
DNS answers can also drive:
ipsetnftset- MikroTik route sync
- reverse lookup caches
That is why side-effect isolation and post-response execution are treated as architectural concerns, not bolt-ons.
Why ForgeDNS Uses Its Own DNS Message Layer
ForgeDNS keeps its own DNS model and wire codec instead of building the full path on top of opaque third-party message objects.
Main reasons:
- Easier hot-path optimization
- Cleaner access to DNS semantics in policy code
- Tighter control over protocol correctness and server behavior
At a high level there are two layers:
- model layer:
Message,Name,Record,RData - wire layer: encode/decode, compression, length estimation, truncation, and RDATA rules
Performance Principles
- Keep listeners thin and route policy into
sequence. - Do work at startup when possible, not per request.
- Treat upstream connections as reusable resources.
- Keep logging, metrics, and route sync off the critical path when correctness allows.
- Respect TTL and negative-cache semantics.
- Watch lock contention and shared-state growth.