How v2rayN Implements DNS Service for V2Ray and Singbox Cores: A Technical Deep Dive
v2rayN generates DNS configurations programmatically through two dedicated services—V2rayDnsService for V2Ray/Xray cores and SingboxDnsService for Singbox—each building core-specific JSON schemas with distinct tagging strategies and routing rules.
The v2rayN client (available at 2dust/v2rayN) abstracts DNS configuration generation behind core-specific services that translate user settings into executable JSON configs. Whether routing traffic through V2Ray/Xray or Singbox, the application dynamically constructs DNS servers, routing rules, and resolver chains based on the selected core type. This article examines the source code implementation to reveal how v2rayN handles DNS service implementation for each proxy core.
Architectural Overview of v2rayN DNS Implementation
v2rayN delegates DNS configuration to two specialized services located in v2rayN/ServiceLib/Services/CoreConfig/. For V2Ray/Xray cores, the V2rayDnsService class constructs a Dns4Ray object, while Singbox cores utilize SingboxDnsService to build a Dns4Sbox structure.
Both services follow an identical high-level workflow:
- Check for custom DNS configurations (
RawDnsItem.Enabled) - Generate server lists (direct, remote, bootstrap, hosts)
- Create routing rules mapping domains to specific DNS servers
- Determine the final resolver tag based on the last routing rule's outbound target
V2Ray DNS Implementation in v2rayN
The V2rayDnsService Class
Located in v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs, this service is invoked by CoreConfigV2rayService.GenerateClientConfigContent() at line 59. It constructs a single DNS configuration object that populates the <dns> section of the V2Ray configuration and creates a corresponding field rule under <routing.rules>.
Configuration Generation Process
The service operates through two primary pathways:
- Custom DNS Injection: When
RawDnsItem.Enabledis true, the service callsGenDnsCustom()to inject user-provided JSON directly into the configuration. - Dynamic DNS Building: Otherwise, it executes
GenDns()which parses Direct, Remote, and Bootstrap DNS addresses viaParseDnsAddresses(), creates server entries viaCreateDnsServer(), and assigns the tagGlobal.DnsTagto the DNS object.
The service then creates a field rule binding inbound tag dns to the outbound tag determined by BuildFinalRule().
Code Example: Building the DNS Section
// Inside V2rayDnsService.GenDns()
var simpleDnsItem = context.SimpleDnsItem;
var dnsItem = _coreConfig.dns is Dns4Ray dns4Ray ? dns4Ray : new Dns4Ray();
var directDNS = ParseDnsAddresses(simpleDnsItem?.DirectDNS,
Global.DomainDirectDNSAddress.First());
var remoteDNS = ParseDnsAddresses(simpleDnsItem?.RemoteDNS,
Global.DomainRemoteDNSAddress.First());
// Fill server lists …
AddDnsServers(remoteDNS, proxyDomainList);
AddDnsServers(directDNS, directDomainList);
// Set the DNS tag used by the routing rule
dnsItem.tag = Global.DnsTag;
// Create a routing rule that sends DNS queries to the chosen outbound
var finalRule = BuildFinalRule();
_coreConfig.routing.rules.Add(new()
{
type = "field",
inboundTag = [Global.DnsTag],
outboundTag = finalRule.outboundTag,
balancerTag = finalRule.balancerTag
});
_coreConfig.dns = dnsItem;
Source: V2rayDnsService.cs lines 70-84 and 96-108
Singbox DNS Implementation in v2rayN
The SingboxDnsService Class
Found in v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs, this service is called from CoreConfigSingboxService.GenerateClientConfigContent() at line 54. Unlike the V2Ray implementation, Singbox uses a multi-server architecture with distinct tags for different DNS paths.
Multi-Tag Server Architecture
The service generates a Dns4Sbox object containing multiple tagged servers:
- Remote DNS: Tagged as
Global.SingboxRemoteDNSTag(typically"remote_dns"), routed through the proxy outbound via thedetourfield - Direct DNS: Tagged as
Global.SingboxDirectDNSTag(typically"direct_dns"), used for direct connections - Hosts DNS: Tagged as
Global.SingboxHostsDNSTagwithtype = "hosts", containing predefined and system hosts - Bootstrap DNS: Tagged as
Global.SingboxLocalDNSTag, used for bootstrapping - FakeIP DNS: Tagged as
Global.SingboxFakeIPTagwhen FakeIP is enabled
Code Example: DNS Servers and Rules
// Inside SingboxDnsService.GenDnsServers()
var simple = context.SimpleDnsItem;
var direct = ParseDnsAddress(simple.DirectDNS ?? Global.DomainDirectDNSAddress.First());
direct.tag = Global.SingboxDirectDNSTag;
direct.domain_resolver = Global.SingboxLocalDNSTag;
var remote = ParseDnsAddress(simple.RemoteDNS ?? Global.DomainRemoteDNSAddress.First());
remote.tag = Global.SingboxRemoteDNSTag;
remote.detour = Global.ProxyTag;
remote.domain_resolver = Global.SingboxLocalDNSTag;
// hosts server (predefined + system + custom)
var hosts = new Server4Sbox { tag = Global.SingboxHostsDNSTag, type = "hosts", predefined = new() };
if (simple.AddCommonHosts) hosts.predefined = Global.PredefinedHosts;
if (simple.UseSystemHosts) hosts.predefined.AddRange(Utils.GetSystemHosts());
// Add servers to core config
_coreConfig.dns.servers.AddRange(new[] { remote, direct, hosts });
// -----------------------------------------------------------------
// Inside SingboxDnsService.GenDnsRules()
var rule = new Rule4Sbox
{
server = Global.SingboxDirectDNSTag,
strategy = Utils.DomainStrategy4Sbox(simple.Strategy4Freedom),
domain = context.ProtectDomainList.ToList()
};
_coreConfig.dns.rules.Add(rule);
Source: SingboxDnsService.cs lines 62-71 and 76-84
Key Differences Between V2Ray and Singbox DNS in v2rayN
| Aspect | V2Ray Implementation | Singbox Implementation |
|---|---|---|
| Configuration Object | Dns4Ray (custom C# class) |
Dns4Sbox (matches Singbox JSON schema) |
| Server Tags | Single tag Global.DnsTag for DNS inbound/outbound pair | Distinct tags: direct_dns, remote_dns, hosts_dns, bootstrap_dns, fake_dns |
| Domain Strategy | Set on freedom outbound and direct/proxy outbounds via strategy4Freedom and strategy4Proxy | Built into Rule4Sbox objects with strategy field from Utils.DomainStrategy4Sbox() |
| Hosts Handling | Merged into dns.hosts dictionary | Dedicated hosts server with type = "hosts" and predefined dictionary |
| Bootstrap DNS | Added only when dnsServerDomains are present | Always created via GenBootstrapDns() |
| Final Resolver | Decides default server list based on last routing rule's outbound tag | Sets dns.final tag to direct_dns or remote_dns based on routing heuristic |
| Fake-IP Support | Fake-ip server added only for remote DNS path when enabled | Dedicated fakeip server with logical rules for query rewriting |
Determining the Final DNS Resolver
Both services use identical heuristics to determine whether to use direct or remote DNS as the default resolver. They analyze the last routing rule: if the final rule routes to Global.DirectTag, the system uses direct DNS; otherwise, it defaults to remote DNS.
For V2Ray, this affects which server list is added to dnsItem.servers:
// V2Ray – decides default DNS servers based on the last routing rule
var useDirectDns = false;
if (rules?.LastOrDefault() is { OutboundTag: Global.DirectTag })
useDirectDns = true;
var defaultDnsServers = useDirectDns ? directDNSAddress : remoteDNSAddress;
dnsItem.servers.AddRange(defaultDnsServers);
Source: V2rayDnsService.cs lines 26-38
For Singbox, this sets the dns.final field:
// Singbox – same heuristic, but sets the final tag
var useDirectDns = false;
if (rules?.LastOrDefault() is { OutboundTag: Global.DirectTag })
useDirectDns = true;
_coreConfig.dns.final = useDirectDns ? Global.SingboxDirectDNSTag
: Global.SingboxRemoteDNSTag;
Source: SingboxDnsService.cs lines 24-38
Summary
- v2rayN implements DNS generation through two dedicated services:
V2rayDnsServicefor V2Ray/Xray andSingboxDnsServicefor Singbox cores. - V2Ray uses a monolithic DNS configuration with a single tag and field-based routing rules, while Singbox employs multiple tagged servers with complex rule chains.
- Both services support custom DNS JSON injection via
GenDnsCustom()whenRawDnsItem.Enabledis true. - The final DNS resolver is determined by analyzing the last routing rule's outbound tag—if it points to
Global.DirectTag, direct DNS is used; otherwise, remote DNS is selected. - Source constants and tags are defined in
Global.cs, includingSingboxDirectDNSTag,SingboxRemoteDNSTag, andDnsTag.
Frequently Asked Questions
How does v2rayN handle custom DNS configurations for different cores?
When RawDnsItem.Enabled is true, v2rayN bypasses automatic generation. For V2Ray, GenDnsCustom() merges user-provided JSON with system hosts. For Singbox, it deserializes the JSON directly into a Dns4Sbox object and applies protect customizations if needed.
What is the difference between direct_dns and remote_dns tags in Singbox?
According to the source code in Global.cs, SingboxDirectDNSTag (mapped to "direct_dns") handles queries for direct connections, while SingboxRemoteDNSTag (mapped to "remote_dns") handles queries routed through the proxy. The detour field on the remote server points to Global.ProxyTag, ensuring DNS queries use the proxy tunnel.
How does v2rayN decide which DNS server to use as the final resolver?
Both implementations check the last routing rule in the configuration chain. If rules.LastOrDefault().OutboundTag equals Global.DirectTag, the system selects direct DNS; otherwise, it selects remote DNS. In Singbox, this sets the dns.final field; in V2Ray, it determines which server list populates the default DNS entries.
Where are the DNS service implementations located in the v2rayN source code?
The V2Ray DNS service resides in v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs, invoked by CoreConfigV2rayService.cs at line 59. The Singbox DNS service is located at v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs, called from CoreConfigSingboxService.cs at line 54. Shared constants are defined in v2rayN/ServiceLib/Global.cs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →