DomainResolver
DomainResolver is an advanced support node that resolves a line's destination domain before forwarding that line's 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 - perform packet-line work
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 can technically receive upstream or downstream Init, but normal manual use is upstream in the middle of a stream chain.
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
The downstream direction behaves the same way, but forwards the delayed Init to the previous node.
Pending Payloads
Payloads that arrive from the initiating side while DNS is pending are queued. The queue limit is 1 MiB per line.
The limit is checked after enqueue, so the pending queue may exceed the limit by one buffer before the line is closed. If DNS fails or the queue overflows, the node destroys its own line state and finishes only the side that initiated the unresolved line.
Callbacks other than payload are ignored until the resolver reaches open state.
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
| Property | Value |
|---|---|
| Intended audience | Advanced users and internal node composition |
| Position | Middle stream support node |
| Layer group | Anything to anything |
| Per-line state | Yes |
| Creates lines | No |
| Destroys lines | No |
| Modifies payload | No |
| Required left padding | 0 |