DomainResolver
DomainResolver is an advanced support node that resolves a line's destination domain before forwarding that line's upstream Init.
Normal users usually should not configure this node manually. Several higher-level nodes create and configure it internally, including TcpConnector, UdpConnector, Router, Socks5Client, VlessClient, and TrojanClient. Use the public settings on those nodes first unless you are deliberately building a custom chain that sets line->routing_context.dest_ctx yourself.
What It Does
DomainResolver reads and updates the line destination address context:
line->routing_context.dest_ctx
If the destination is already an IP address, or has already been resolved, DomainResolver forwards Init immediately. If the destination is a domain name, it submits asynchronous DNS on the current worker, applies the configured domain strategy, writes the selected IP back into dest_ctx, then forwards the delayed Init.
It does not:
- open sockets
- create lines
- transform payload bytes
- prepend protocol data
- resolve
src_ctx
Typical Placement
Manual placement is advanced. Put it after a node that sets dest_ctx to a domain and before a node that requires a concrete IP address.
TcpListener -> Socks5Server -> DomainResolver -> TcpConnector
In many real configs this is unnecessary because the connector/protocol node inserts its own internal resolver.
Basic Example
{
"name": "resolve-domain",
"type": "DomainResolver",
"settings": {
"strategy": "prefer-ipv4",
"verbose": false
},
"next": "outbound"
}
Fields
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Must be DomainResolver. |
settings | object | No | Optional settings object. If present, it must be an object. |
next | string | Usually | The node that receives the line after destination resolution in the upstream direction. |
DomainResolver accepts upstream Init and downstream Est. Downstream Init and upstream Est use the constructor defaults that reject unsupported callbacks. Payload, Pause/Resume, and Finish retain their ordinary bidirectional meanings.
Settings
| Field | Default | Description |
|---|---|---|
strategy | core dns.domain-strategy | DNS result selection strategy. Accepts core-settings, accept-dns-returned-order, prefer-ipv4, prefer-ipv6, only-ipv4, or only-ipv6. |
verbose | false | Logs DNS start messages at debug level. Resolved-address logs still use the normal DNS debug logger. |
strategy can be given as a string or as the internal domain-strategy value accepted by the shared parser.
Runtime Flow
On upstream Init:
- line state is initialized
dest_ctxis inspected- if no DNS is needed, upstream
Initis forwarded tonext - if DNS is needed, the node enters resolving state and returns
- when DNS completes, the selected address is written into
dest_ctx - the delayed upstream
Initis forwarded - payloads queued during DNS are replayed upstream
Downstream payloads forward directly once next Init has started, including replies during Init itself.
Pending Payloads
Upstream payloads are retained during DNS, adjacent Init reentry, or an older ordered backlog. Admission checks both logical bytes and retained allocation charge against 2 MiB per line before enqueue. Overflow closes only prev before next Init, or both initialized directions afterwards.
Transport Est forwards promptly once the path opens. The backlog drains in FIFO order while the consumer permits it; nested input cannot overtake older input. Pause received during DNS remains effective when the adjacent path opens.
The first retained input pauses only the initiating source, after FIFO ownership and accounting are published. This local DNS/order hold is separate from received Pause permission and does not pause DNS or the transport being initialized. It stays active through drain callbacks and is released only when the FIFO is empty and the adjacent consumer permits sending. Reentrant Pause/Resume cannot overtake older input, clear another pressure reason, or resurrect work after Finish.
Once next Init has returned, the pending FIFO is empty and local pressure
notifications are settled, a normal line permanently bypasses this node. The
resolver destroys and zeros its full line state first, including any embedded
preparation storage. Nodes using that storage must consume or copy it during
Init; it is unavailable afterward. Later callbacks go directly between the
resolver's neighbors, and no later Finish reaches the resolver. Actual worker
packet lines remain active.
Failure Behavior
The line is rejected when:
- the destination is not an IP address and not a domain
- async DNS submission fails
- DNS returns no usable address for the configured strategy
- the pending payload queue exceeds its limit
DomainResolver does not retry DNS by itself. Retry behavior belongs in the higher-level node or transport design.
Node Metadata
DomainResolver is an internal transparent support node: it keeps per-line state but neither creates nor destroys lines or changes payload bytes.
Source-backed metadata:
| Property | Value |
|---|---|
| node flags | kNodeFlagSupportsSplice |
can_have_prev | true |
can_have_next | true |
layer_group | kNodeLayerAnything |
layer_group_prev_node | kNodeLayerSameAsNext |
layer_group_next_node | kNodeLayerSameAsPrev |
required_padding_left | 0 bytes |