Browse Source

[app/dns] Support per-client configuration for fakedns (#2212)

* Move `filterIP` from `hosts.go` to `dnscommon.go`

* Implement adding pools for fakedns.HolderMulti

* Implement per-client fakedns for DNS app

* Remove `dns.ClientWithIPOption` and replace with new programming model

* Implement JSON config support for new fakedns config

* Fix lint and tests

* Fix some codacy analysis
Vigilans 2 years ago
parent
commit
f8ac919d66

+ 312 - 250
app/dns/config.pb.go

@@ -1,6 +1,7 @@
 package dns
 package dns
 
 
 import (
 import (
+	fakedns "github.com/v2fly/v2ray-core/v5/app/dns/fakedns"
 	routercommon "github.com/v2fly/v2ray-core/v5/app/router/routercommon"
 	routercommon "github.com/v2fly/v2ray-core/v5/app/router/routercommon"
 	net "github.com/v2fly/v2ray-core/v5/common/net"
 	net "github.com/v2fly/v2ray-core/v5/common/net"
 	_ "github.com/v2fly/v2ray-core/v5/common/protoext"
 	_ "github.com/v2fly/v2ray-core/v5/common/protoext"
@@ -224,6 +225,7 @@ type NameServer struct {
 	PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
 	PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
 	Geoip             []*routercommon.GeoIP        `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
 	Geoip             []*routercommon.GeoIP        `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
 	OriginalRules     []*NameServer_OriginalRule   `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
 	OriginalRules     []*NameServer_OriginalRule   `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
+	FakeDns           *fakedns.FakeDnsPoolMulti    `protobuf:"bytes,11,opt,name=fake_dns,json=fakeDns,proto3" json:"fake_dns,omitempty"`
 	// Deprecated. Use fallback_strategy.
 	// Deprecated. Use fallback_strategy.
 	//
 	//
 	// Deprecated: Do not use.
 	// Deprecated: Do not use.
@@ -307,6 +309,13 @@ func (x *NameServer) GetOriginalRules() []*NameServer_OriginalRule {
 	return nil
 	return nil
 }
 }
 
 
+func (x *NameServer) GetFakeDns() *fakedns.FakeDnsPoolMulti {
+	if x != nil {
+		return x.FakeDns
+	}
+	return nil
+}
+
 // Deprecated: Do not use.
 // Deprecated: Do not use.
 func (x *NameServer) GetSkipFallback() bool {
 func (x *NameServer) GetSkipFallback() bool {
 	if x != nil {
 	if x != nil {
@@ -429,8 +438,11 @@ type Config struct {
 	Hosts map[string]*net.IPOrDomain `protobuf:"bytes,2,rep,name=Hosts,proto3" json:"Hosts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 	Hosts map[string]*net.IPOrDomain `protobuf:"bytes,2,rep,name=Hosts,proto3" json:"Hosts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 	// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
 	// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
 	// (IPv6).
 	// (IPv6).
-	ClientIp    []byte         `protobuf:"bytes,3,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
+	ClientIp []byte `protobuf:"bytes,3,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
+	// Static domain-ip mapping in DNS server.
 	StaticHosts []*HostMapping `protobuf:"bytes,4,rep,name=static_hosts,json=staticHosts,proto3" json:"static_hosts,omitempty"`
 	StaticHosts []*HostMapping `protobuf:"bytes,4,rep,name=static_hosts,json=staticHosts,proto3" json:"static_hosts,omitempty"`
+	// Global fakedns object.
+	FakeDns *fakedns.FakeDnsPoolMulti `protobuf:"bytes,16,opt,name=fake_dns,json=fakeDns,proto3" json:"fake_dns,omitempty"`
 	// Tag is the inbound tag of DNS client.
 	// Tag is the inbound tag of DNS client.
 	Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
 	Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
 	// Domain matcher to use
 	// Domain matcher to use
@@ -525,6 +537,13 @@ func (x *Config) GetStaticHosts() []*HostMapping {
 	return nil
 	return nil
 }
 }
 
 
+func (x *Config) GetFakeDns() *fakedns.FakeDnsPoolMulti {
+	if x != nil {
+		return x.FakeDns
+	}
+	return nil
+}
+
 func (x *Config) GetTag() string {
 func (x *Config) GetTag() string {
 	if x != nil {
 	if x != nil {
 		return x.Tag
 		return x.Tag
@@ -593,8 +612,11 @@ type SimplifiedConfig struct {
 	NameServer []*SimplifiedNameServer `protobuf:"bytes,5,rep,name=name_server,json=nameServer,proto3" json:"name_server,omitempty"`
 	NameServer []*SimplifiedNameServer `protobuf:"bytes,5,rep,name=name_server,json=nameServer,proto3" json:"name_server,omitempty"`
 	// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
 	// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
 	// (IPv6).
 	// (IPv6).
-	ClientIp    string         `protobuf:"bytes,3,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
+	ClientIp string `protobuf:"bytes,3,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
+	// Static domain-ip mapping in DNS server.
 	StaticHosts []*HostMapping `protobuf:"bytes,4,rep,name=static_hosts,json=staticHosts,proto3" json:"static_hosts,omitempty"`
 	StaticHosts []*HostMapping `protobuf:"bytes,4,rep,name=static_hosts,json=staticHosts,proto3" json:"static_hosts,omitempty"`
+	// Global fakedns object.
+	FakeDns *fakedns.FakeDnsPoolMulti `protobuf:"bytes,16,opt,name=fake_dns,json=fakeDns,proto3" json:"fake_dns,omitempty"`
 	// Tag is the inbound tag of DNS client.
 	// Tag is the inbound tag of DNS client.
 	Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
 	Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
 	// Domain matcher to use
 	// Domain matcher to use
@@ -673,6 +695,13 @@ func (x *SimplifiedConfig) GetStaticHosts() []*HostMapping {
 	return nil
 	return nil
 }
 }
 
 
+func (x *SimplifiedConfig) GetFakeDns() *fakedns.FakeDnsPoolMulti {
+	if x != nil {
+		return x.FakeDns
+	}
+	return nil
+}
+
 func (x *SimplifiedConfig) GetTag() string {
 func (x *SimplifiedConfig) GetTag() string {
 	if x != nil {
 	if x != nil {
 		return x.Tag
 		return x.Tag
@@ -816,6 +845,7 @@ type SimplifiedNameServer struct {
 	PrioritizedDomain []*SimplifiedNameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
 	PrioritizedDomain []*SimplifiedNameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
 	Geoip             []*routercommon.GeoIP                  `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
 	Geoip             []*routercommon.GeoIP                  `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
 	OriginalRules     []*SimplifiedNameServer_OriginalRule   `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
 	OriginalRules     []*SimplifiedNameServer_OriginalRule   `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
+	FakeDns           *fakedns.FakeDnsPoolMulti              `protobuf:"bytes,11,opt,name=fake_dns,json=fakeDns,proto3" json:"fake_dns,omitempty"`
 	// Deprecated. Use fallback_strategy.
 	// Deprecated. Use fallback_strategy.
 	//
 	//
 	// Deprecated: Do not use.
 	// Deprecated: Do not use.
@@ -899,6 +929,13 @@ func (x *SimplifiedNameServer) GetOriginalRules() []*SimplifiedNameServer_Origin
 	return nil
 	return nil
 }
 }
 
 
+func (x *SimplifiedNameServer) GetFakeDns() *fakedns.FakeDnsPoolMulti {
+	if x != nil {
+		return x.FakeDns
+	}
+	return nil
+}
+
 // Deprecated: Do not use.
 // Deprecated: Do not use.
 func (x *SimplifiedNameServer) GetSkipFallback() bool {
 func (x *SimplifiedNameServer) GetSkipFallback() bool {
 	if x != nil {
 	if x != nil {
@@ -1159,92 +1196,153 @@ var file_app_dns_config_proto_rawDesc = []byte{
 	0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f,
 	0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x1a, 0x24, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x72,
 	0x74, 0x6f, 0x1a, 0x24, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x72,
 	0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
 	0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
-	0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
-	0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78, 0x74, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
-	0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe1, 0x06, 0x0a, 0x0a, 0x4e,
-	0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x07, 0x61, 0x64, 0x64,
-	0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72,
-	0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e,
-	0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x07, 0x61, 0x64, 0x64,
-	0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69,
-	0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49,
-	0x70, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
-	0x74, 0x61, 0x67, 0x12, 0x5c, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a,
-	0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
-	0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
-	0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e,
-	0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11,
-	0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69,
-	0x6e, 0x12, 0x3f, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x29, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
-	0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63,
-	0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f,
-	0x69, 0x70, 0x12, 0x52, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72,
-	0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72,
-	0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e,
-	0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69,
-	0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61,
-	0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61,
-	0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01,
-	0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x4d,
-	0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
-	0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
-	0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72,
-	0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x48, 0x00, 0x52, 0x0d, 0x71, 0x75, 0x65,
-	0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x88, 0x01, 0x01, 0x12, 0x4d, 0x0a,
-	0x0e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18,
-	0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
-	0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65,
-	0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x48, 0x01, 0x52, 0x0d, 0x63, 0x61, 0x63, 0x68,
-	0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x88, 0x01, 0x01, 0x12, 0x56, 0x0a, 0x11,
-	0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
-	0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
-	0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6c,
-	0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x48, 0x02, 0x52,
-	0x10, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
-	0x79, 0x88, 0x01, 0x01, 0x1a, 0x64, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79,
-	0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
-	0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
-	0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79,
-	0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72,
-	0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75,
-	0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12,
-	0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69,
-	0x7a, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72,
-	0x61, 0x74, 0x65, 0x67, 0x79, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f,
-	0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x66, 0x61, 0x6c,
-	0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0x98,
-	0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3a,
+	0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e,
+	0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
+	0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78, 0x74, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xaa, 0x07, 0x0a, 0x0a, 0x4e, 0x61,
+	0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72,
+	0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61,
+	0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
+	0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72,
+	0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70,
+	0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74,
+	0x61, 0x67, 0x12, 0x5c, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65,
+	0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d,
+	0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
+	0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50,
+	0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70,
+	0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
+	0x12, 0x3f, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x29, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
+	0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6f,
+	0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f, 0x69,
+	0x70, 0x12, 0x52, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75,
+	0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61,
+	0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e,
+	0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e,
+	0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
+	0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x47, 0x0a, 0x08, 0x66, 0x61, 0x6b, 0x65, 0x5f, 0x64, 0x6e,
+	0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
+	0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b,
+	0x65, 0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c,
+	0x4d, 0x75, 0x6c, 0x74, 0x69, 0x52, 0x07, 0x66, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x12, 0x26,
+	0x0a, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61,
+	0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x4d, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f,
+	0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21,
+	0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
+	0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
+	0x79, 0x48, 0x00, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
+	0x67, 0x79, 0x88, 0x01, 0x01, 0x12, 0x4d, 0x0a, 0x0e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x73,
+	0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e,
+	0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64,
+	0x6e, 0x73, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
+	0x48, 0x01, 0x52, 0x0d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
+	0x79, 0x88, 0x01, 0x01, 0x12, 0x56, 0x0a, 0x11, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
+	0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
+	0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72,
+	0x61, 0x74, 0x65, 0x67, 0x79, 0x48, 0x02, 0x52, 0x10, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
+	0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x88, 0x01, 0x01, 0x1a, 0x64, 0x0a, 0x0e,
+	0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3a,
 	0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x76,
 	0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x76,
 	0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e,
 	0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e,
 	0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67,
 	0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67,
 	0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f,
 	0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f,
 	0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61,
 	0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61,
-	0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02,
-	0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f,
-	0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78,
-	0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0xc7, 0x06, 0x0a, 0x06, 0x43, 0x6f,
-	0x6e, 0x66, 0x69, 0x67, 0x12, 0x45, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76,
-	0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61,
-	0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
-	0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b,
-	0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x3f, 0x0a, 0x0b, 0x6e,
-	0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
-	0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
-	0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x05,
-	0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x76, 0x32,
-	0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73,
-	0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74,
-	0x72, 0x79, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a,
-	0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
-	0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x42, 0x0a, 0x0c, 0x73, 0x74,
-	0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
-	0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
-	0x67, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10,
+	0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75,
+	0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x71,
+	0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x42, 0x11, 0x0a,
+	0x0f, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
+	0x42, 0x14, 0x0a, 0x12, 0x5f, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x73, 0x74,
+	0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0x98, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d,
+	0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
+	0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
+	0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79,
+	0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70,
+	0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72,
+	0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69,
+	0x6e, 0x22, 0x90, 0x07, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x45, 0x0a, 0x0b,
+	0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63,
+	0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69,
+	0x6e, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76,
+	0x65, 0x72, 0x73, 0x12, 0x3f, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76,
+	0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
+	0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61,
+	0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65,
+	0x72, 0x76, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
+	0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
+	0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05,
+	0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f,
+	0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
+	0x49, 0x70, 0x12, 0x42, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f, 0x73,
+	0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
+	0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x48, 0x6f,
+	0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69,
+	0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x47, 0x0a, 0x08, 0x66, 0x61, 0x6b, 0x65, 0x5f, 0x64,
+	0x6e, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
+	0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61,
+	0x6b, 0x65, 0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f,
+	0x6c, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x52, 0x07, 0x66, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x12,
+	0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61,
+	0x67, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63,
+	0x68, 0x65, 0x72, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x6f, 0x6d, 0x61, 0x69,
+	0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61,
+	0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02,
+	0x18, 0x01, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65,
+	0x12, 0x2c, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62,
+	0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0f, 0x64,
+	0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x3a,
+	0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
+	0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02,
+	0x18, 0x01, 0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62,
+	0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x48, 0x0a, 0x0e, 0x71, 0x75,
+	0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01,
+	0x28, 0x0e, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
+	0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72,
+	0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61,
+	0x74, 0x65, 0x67, 0x79, 0x12, 0x48, 0x0a, 0x0e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x73, 0x74,
+	0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x76,
+	0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e,
+	0x73, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52,
+	0x0d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x51,
+	0x0a, 0x11, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74,
+	0x65, 0x67, 0x79, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61,
+	0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x46,
+	0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52,
+	0x10, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
+	0x79, 0x1a, 0x5b, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+	0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+	0x79, 0x12, 0x37, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,
+	0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d,
+	0x61, 0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04,
+	0x08, 0x07, 0x10, 0x08, 0x22, 0xe3, 0x05, 0x0a, 0x10, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66,
+	0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x49, 0x0a, 0x0b, 0x6e, 0x61, 0x6d,
+	0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28,
+	0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
+	0x64, 0x6e, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x4e, 0x61,
+	0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65,
+	0x72, 0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69,
+	0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49,
+	0x70, 0x12, 0x42, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74,
+	0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
+	0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x48, 0x6f, 0x73,
+	0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63,
+	0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x47, 0x0a, 0x08, 0x66, 0x61, 0x6b, 0x65, 0x5f, 0x64, 0x6e,
+	0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
+	0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b,
+	0x65, 0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c,
+	0x4d, 0x75, 0x6c, 0x74, 0x69, 0x52, 0x07, 0x66, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x12, 0x10,
 	0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67,
 	0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67,
 	0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68,
 	0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68,
 	0x65, 0x72, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
 	0x65, 0x72, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
@@ -1272,143 +1370,102 @@ var file_app_dns_config_proto_rawDesc = []byte{
 	0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61,
 	0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61,
 	0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x10,
 	0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x10,
 	0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
 	0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
-	0x1a, 0x5b, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
-	0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
-	0x12, 0x37, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
-	0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
-	0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61,
-	0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08,
-	0x07, 0x10, 0x08, 0x22, 0x9a, 0x05, 0x0a, 0x10, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69,
-	0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x49, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65,
-	0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e,
-	0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64,
-	0x6e, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x4e, 0x61, 0x6d,
-	0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72,
-	0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70,
-	0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70,
-	0x12, 0x42, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73,
-	0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
-	0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x48, 0x6f, 0x73, 0x74,
-	0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48,
-	0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
-	0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
-	0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x26, 0x0a,
-	0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20,
-	0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
-	0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x2c, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
-	0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02,
-	0x18, 0x01, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62,
-	0x61, 0x63, 0x6b, 0x12, 0x3a, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61,
-	0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20,
-	0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
-	0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12,
-	0x48, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
-	0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
-	0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65,
-	0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72,
-	0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x48, 0x0a, 0x0e, 0x63, 0x61, 0x63,
-	0x68, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28,
+	0x3a, 0x16, 0x82, 0xb5, 0x18, 0x09, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x82,
+	0xb5, 0x18, 0x05, 0x12, 0x03, 0x64, 0x6e, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04,
+	0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x22, 0xa2, 0x01, 0x0a, 0x15, 0x53,
+	0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70,
+	0x70, 0x69, 0x6e, 0x67, 0x12, 0x3a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0e, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
+	0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61,
+	0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
+	0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78,
+	0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22,
+	0xc8, 0x07, 0x0a, 0x14, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x4e, 0x61,
+	0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72,
+	0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61,
+	0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
+	0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72,
+	0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70,
+	0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74,
+	0x61, 0x67, 0x12, 0x66, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65,
+	0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37,
+	0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
+	0x64, 0x6e, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x4e, 0x61,
+	0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74,
+	0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74,
+	0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3f, 0x0a, 0x05, 0x67, 0x65,
+	0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x76, 0x32, 0x72, 0x61,
+	0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
+	0x72, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x47,
+	0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x5c, 0x0a, 0x0e, 0x6f,
+	0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
+	0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66,
+	0x69, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72,
+	0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67,
+	0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x47, 0x0a, 0x08, 0x66, 0x61, 0x6b,
+	0x65, 0x5f, 0x64, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x76, 0x32,
+	0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73,
+	0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73,
+	0x50, 0x6f, 0x6f, 0x6c, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x52, 0x07, 0x66, 0x61, 0x6b, 0x65, 0x44,
+	0x6e, 0x73, 0x12, 0x26, 0x0a, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61,
+	0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x73, 0x6b,
+	0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x4d, 0x0a, 0x0e, 0x71, 0x75,
+	0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x08, 0x20, 0x01,
+	0x28, 0x0e, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
+	0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72,
+	0x61, 0x74, 0x65, 0x67, 0x79, 0x48, 0x00, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74,
+	0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x88, 0x01, 0x01, 0x12, 0x4d, 0x0a, 0x0e, 0x63, 0x61, 0x63,
+	0x68, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28,
 	0x0e, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
 	0x0e, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
 	0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61,
 	0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61,
-	0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74,
-	0x65, 0x67, 0x79, 0x12, 0x51, 0x0a, 0x11, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f,
-	0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24,
-	0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
-	0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61,
-	0x74, 0x65, 0x67, 0x79, 0x52, 0x10, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74,
-	0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x3a, 0x16, 0x82, 0xb5, 0x18, 0x09, 0x0a, 0x07, 0x73, 0x65,
-	0x72, 0x76, 0x69, 0x63, 0x65, 0x82, 0xb5, 0x18, 0x05, 0x12, 0x03, 0x64, 0x6e, 0x73, 0x4a, 0x04,
-	0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08,
-	0x22, 0xa2, 0x01, 0x0a, 0x15, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x48,
-	0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3a, 0x0a, 0x04, 0x74, 0x79,
-	0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
-	0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f,
+	0x74, 0x65, 0x67, 0x79, 0x48, 0x01, 0x52, 0x0d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72,
+	0x61, 0x74, 0x65, 0x67, 0x79, 0x88, 0x01, 0x01, 0x12, 0x56, 0x0a, 0x11, 0x66, 0x61, 0x6c, 0x6c,
+	0x62, 0x61, 0x63, 0x6b, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x0a, 0x20,
+	0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
+	0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
+	0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x48, 0x02, 0x52, 0x10, 0x66, 0x61, 0x6c,
+	0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x88, 0x01, 0x01,
+	0x1a, 0x64, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61,
+	0x69, 0x6e, 0x12, 0x3a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
+	0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
+	0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63,
+	0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16,
+	0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
+	0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e,
+	0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69,
+	0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x11,
+	0x0a, 0x0f, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
+	0x79, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x61,
+	0x74, 0x65, 0x67, 0x79, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
+	0x6b, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f,
 	0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65,
 	0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65,
-	0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e,
-	0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25,
-	0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44,
-	0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0xff, 0x06, 0x0a, 0x14, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69,
-	0x66, 0x69, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x39,
-	0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
-	0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
-	0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
-	0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69,
-	0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c,
-	0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x07, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x66, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6f,
-	0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
-	0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69,
-	0x66, 0x69, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50,
-	0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70,
-	0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
-	0x12, 0x3f, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
-	0x29, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
-	0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x63, 0x6f,
-	0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f, 0x69,
-	0x70, 0x12, 0x5c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75,
-	0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x76, 0x32, 0x72, 0x61,
-	0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x53,
-	0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72,
-	0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65,
-	0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12,
-	0x26, 0x0a, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18,
-	0x06, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46,
-	0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x4d, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79,
-	0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32,
-	0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
-	0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
-	0x67, 0x79, 0x48, 0x00, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74,
-	0x65, 0x67, 0x79, 0x88, 0x01, 0x01, 0x12, 0x4d, 0x0a, 0x0e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f,
-	0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21,
-	0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
-	0x64, 0x6e, 0x73, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
-	0x79, 0x48, 0x01, 0x52, 0x0d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
-	0x67, 0x79, 0x88, 0x01, 0x01, 0x12, 0x56, 0x0a, 0x11, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
-	0x6b, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e,
-	0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
-	0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74,
-	0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x48, 0x02, 0x52, 0x10, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61,
-	0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x88, 0x01, 0x01, 0x1a, 0x64, 0x0a,
-	0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12,
-	0x3a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e,
-	0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64,
-	0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e,
-	0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64,
-	0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d,
-	0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52,
-	0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f,
-	0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x42, 0x11,
-	0x0a, 0x0f, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
-	0x79, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x73,
-	0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69,
-	0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a,
-	0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64, 0x6f,
-	0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72,
-	0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a, 0x35,
-	0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12,
-	0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55,
-	0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f,
-	0x49, 0x50, 0x36, 0x10, 0x02, 0x2a, 0x34, 0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74,
-	0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x61, 0x63, 0x68, 0x65, 0x45,
-	0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68,
-	0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x10, 0x01, 0x2a, 0x45, 0x0a, 0x10, 0x46,
-	0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12,
-	0x0b, 0x0a, 0x07, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08,
-	0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x69,
-	0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x49, 0x66, 0x41, 0x6e, 0x79, 0x4d, 0x61, 0x74, 0x63, 0x68,
-	0x10, 0x02, 0x42, 0x57, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
-	0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x26,
-	0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79,
-	0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x35, 0x2f, 0x61,
-	0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x12, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43,
-	0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x33,
+	0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75,
+	0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79,
+	0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10,
+	0x03, 0x2a, 0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
+	0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b,
+	0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55,
+	0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 0x2a, 0x34, 0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68,
+	0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x61, 0x63,
+	0x68, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x43,
+	0x61, 0x63, 0x68, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x10, 0x01, 0x2a, 0x45,
+	0x0a, 0x10, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
+	0x67, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x10, 0x00, 0x12,
+	0x0c, 0x0a, 0x08, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x10, 0x01, 0x12, 0x16, 0x0a,
+	0x12, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x49, 0x66, 0x41, 0x6e, 0x79, 0x4d, 0x61,
+	0x74, 0x63, 0x68, 0x10, 0x02, 0x42, 0x57, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72,
+	0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50,
+	0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32,
+	0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76,
+	0x35, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x12, 0x56, 0x32, 0x52, 0x61,
+	0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 }
 
 
 var (
 var (
@@ -1443,45 +1500,50 @@ var file_app_dns_config_proto_goTypes = []interface{}{
 	(*SimplifiedNameServer_OriginalRule)(nil),   // 14: v2ray.core.app.dns.SimplifiedNameServer.OriginalRule
 	(*SimplifiedNameServer_OriginalRule)(nil),   // 14: v2ray.core.app.dns.SimplifiedNameServer.OriginalRule
 	(*net.Endpoint)(nil),                        // 15: v2ray.core.common.net.Endpoint
 	(*net.Endpoint)(nil),                        // 15: v2ray.core.common.net.Endpoint
 	(*routercommon.GeoIP)(nil),                  // 16: v2ray.core.app.router.routercommon.GeoIP
 	(*routercommon.GeoIP)(nil),                  // 16: v2ray.core.app.router.routercommon.GeoIP
-	(*net.IPOrDomain)(nil),                      // 17: v2ray.core.common.net.IPOrDomain
+	(*fakedns.FakeDnsPoolMulti)(nil),            // 17: v2ray.core.app.dns.fakedns.FakeDnsPoolMulti
+	(*net.IPOrDomain)(nil),                      // 18: v2ray.core.common.net.IPOrDomain
 }
 }
 var file_app_dns_config_proto_depIdxs = []int32{
 var file_app_dns_config_proto_depIdxs = []int32{
 	15, // 0: v2ray.core.app.dns.NameServer.address:type_name -> v2ray.core.common.net.Endpoint
 	15, // 0: v2ray.core.app.dns.NameServer.address:type_name -> v2ray.core.common.net.Endpoint
 	10, // 1: v2ray.core.app.dns.NameServer.prioritized_domain:type_name -> v2ray.core.app.dns.NameServer.PriorityDomain
 	10, // 1: v2ray.core.app.dns.NameServer.prioritized_domain:type_name -> v2ray.core.app.dns.NameServer.PriorityDomain
 	16, // 2: v2ray.core.app.dns.NameServer.geoip:type_name -> v2ray.core.app.router.routercommon.GeoIP
 	16, // 2: v2ray.core.app.dns.NameServer.geoip:type_name -> v2ray.core.app.router.routercommon.GeoIP
 	11, // 3: v2ray.core.app.dns.NameServer.original_rules:type_name -> v2ray.core.app.dns.NameServer.OriginalRule
 	11, // 3: v2ray.core.app.dns.NameServer.original_rules:type_name -> v2ray.core.app.dns.NameServer.OriginalRule
-	1,  // 4: v2ray.core.app.dns.NameServer.query_strategy:type_name -> v2ray.core.app.dns.QueryStrategy
-	2,  // 5: v2ray.core.app.dns.NameServer.cache_strategy:type_name -> v2ray.core.app.dns.CacheStrategy
-	3,  // 6: v2ray.core.app.dns.NameServer.fallback_strategy:type_name -> v2ray.core.app.dns.FallbackStrategy
-	0,  // 7: v2ray.core.app.dns.HostMapping.type:type_name -> v2ray.core.app.dns.DomainMatchingType
-	15, // 8: v2ray.core.app.dns.Config.NameServers:type_name -> v2ray.core.common.net.Endpoint
-	4,  // 9: v2ray.core.app.dns.Config.name_server:type_name -> v2ray.core.app.dns.NameServer
-	12, // 10: v2ray.core.app.dns.Config.Hosts:type_name -> v2ray.core.app.dns.Config.HostsEntry
-	5,  // 11: v2ray.core.app.dns.Config.static_hosts:type_name -> v2ray.core.app.dns.HostMapping
-	1,  // 12: v2ray.core.app.dns.Config.query_strategy:type_name -> v2ray.core.app.dns.QueryStrategy
-	2,  // 13: v2ray.core.app.dns.Config.cache_strategy:type_name -> v2ray.core.app.dns.CacheStrategy
-	3,  // 14: v2ray.core.app.dns.Config.fallback_strategy:type_name -> v2ray.core.app.dns.FallbackStrategy
-	9,  // 15: v2ray.core.app.dns.SimplifiedConfig.name_server:type_name -> v2ray.core.app.dns.SimplifiedNameServer
-	5,  // 16: v2ray.core.app.dns.SimplifiedConfig.static_hosts:type_name -> v2ray.core.app.dns.HostMapping
-	1,  // 17: v2ray.core.app.dns.SimplifiedConfig.query_strategy:type_name -> v2ray.core.app.dns.QueryStrategy
-	2,  // 18: v2ray.core.app.dns.SimplifiedConfig.cache_strategy:type_name -> v2ray.core.app.dns.CacheStrategy
-	3,  // 19: v2ray.core.app.dns.SimplifiedConfig.fallback_strategy:type_name -> v2ray.core.app.dns.FallbackStrategy
-	0,  // 20: v2ray.core.app.dns.SimplifiedHostMapping.type:type_name -> v2ray.core.app.dns.DomainMatchingType
-	15, // 21: v2ray.core.app.dns.SimplifiedNameServer.address:type_name -> v2ray.core.common.net.Endpoint
-	13, // 22: v2ray.core.app.dns.SimplifiedNameServer.prioritized_domain:type_name -> v2ray.core.app.dns.SimplifiedNameServer.PriorityDomain
-	16, // 23: v2ray.core.app.dns.SimplifiedNameServer.geoip:type_name -> v2ray.core.app.router.routercommon.GeoIP
-	14, // 24: v2ray.core.app.dns.SimplifiedNameServer.original_rules:type_name -> v2ray.core.app.dns.SimplifiedNameServer.OriginalRule
-	1,  // 25: v2ray.core.app.dns.SimplifiedNameServer.query_strategy:type_name -> v2ray.core.app.dns.QueryStrategy
-	2,  // 26: v2ray.core.app.dns.SimplifiedNameServer.cache_strategy:type_name -> v2ray.core.app.dns.CacheStrategy
-	3,  // 27: v2ray.core.app.dns.SimplifiedNameServer.fallback_strategy:type_name -> v2ray.core.app.dns.FallbackStrategy
-	0,  // 28: v2ray.core.app.dns.NameServer.PriorityDomain.type:type_name -> v2ray.core.app.dns.DomainMatchingType
-	17, // 29: v2ray.core.app.dns.Config.HostsEntry.value:type_name -> v2ray.core.common.net.IPOrDomain
-	0,  // 30: v2ray.core.app.dns.SimplifiedNameServer.PriorityDomain.type:type_name -> v2ray.core.app.dns.DomainMatchingType
-	31, // [31:31] is the sub-list for method output_type
-	31, // [31:31] is the sub-list for method input_type
-	31, // [31:31] is the sub-list for extension type_name
-	31, // [31:31] is the sub-list for extension extendee
-	0,  // [0:31] is the sub-list for field type_name
+	17, // 4: v2ray.core.app.dns.NameServer.fake_dns:type_name -> v2ray.core.app.dns.fakedns.FakeDnsPoolMulti
+	1,  // 5: v2ray.core.app.dns.NameServer.query_strategy:type_name -> v2ray.core.app.dns.QueryStrategy
+	2,  // 6: v2ray.core.app.dns.NameServer.cache_strategy:type_name -> v2ray.core.app.dns.CacheStrategy
+	3,  // 7: v2ray.core.app.dns.NameServer.fallback_strategy:type_name -> v2ray.core.app.dns.FallbackStrategy
+	0,  // 8: v2ray.core.app.dns.HostMapping.type:type_name -> v2ray.core.app.dns.DomainMatchingType
+	15, // 9: v2ray.core.app.dns.Config.NameServers:type_name -> v2ray.core.common.net.Endpoint
+	4,  // 10: v2ray.core.app.dns.Config.name_server:type_name -> v2ray.core.app.dns.NameServer
+	12, // 11: v2ray.core.app.dns.Config.Hosts:type_name -> v2ray.core.app.dns.Config.HostsEntry
+	5,  // 12: v2ray.core.app.dns.Config.static_hosts:type_name -> v2ray.core.app.dns.HostMapping
+	17, // 13: v2ray.core.app.dns.Config.fake_dns:type_name -> v2ray.core.app.dns.fakedns.FakeDnsPoolMulti
+	1,  // 14: v2ray.core.app.dns.Config.query_strategy:type_name -> v2ray.core.app.dns.QueryStrategy
+	2,  // 15: v2ray.core.app.dns.Config.cache_strategy:type_name -> v2ray.core.app.dns.CacheStrategy
+	3,  // 16: v2ray.core.app.dns.Config.fallback_strategy:type_name -> v2ray.core.app.dns.FallbackStrategy
+	9,  // 17: v2ray.core.app.dns.SimplifiedConfig.name_server:type_name -> v2ray.core.app.dns.SimplifiedNameServer
+	5,  // 18: v2ray.core.app.dns.SimplifiedConfig.static_hosts:type_name -> v2ray.core.app.dns.HostMapping
+	17, // 19: v2ray.core.app.dns.SimplifiedConfig.fake_dns:type_name -> v2ray.core.app.dns.fakedns.FakeDnsPoolMulti
+	1,  // 20: v2ray.core.app.dns.SimplifiedConfig.query_strategy:type_name -> v2ray.core.app.dns.QueryStrategy
+	2,  // 21: v2ray.core.app.dns.SimplifiedConfig.cache_strategy:type_name -> v2ray.core.app.dns.CacheStrategy
+	3,  // 22: v2ray.core.app.dns.SimplifiedConfig.fallback_strategy:type_name -> v2ray.core.app.dns.FallbackStrategy
+	0,  // 23: v2ray.core.app.dns.SimplifiedHostMapping.type:type_name -> v2ray.core.app.dns.DomainMatchingType
+	15, // 24: v2ray.core.app.dns.SimplifiedNameServer.address:type_name -> v2ray.core.common.net.Endpoint
+	13, // 25: v2ray.core.app.dns.SimplifiedNameServer.prioritized_domain:type_name -> v2ray.core.app.dns.SimplifiedNameServer.PriorityDomain
+	16, // 26: v2ray.core.app.dns.SimplifiedNameServer.geoip:type_name -> v2ray.core.app.router.routercommon.GeoIP
+	14, // 27: v2ray.core.app.dns.SimplifiedNameServer.original_rules:type_name -> v2ray.core.app.dns.SimplifiedNameServer.OriginalRule
+	17, // 28: v2ray.core.app.dns.SimplifiedNameServer.fake_dns:type_name -> v2ray.core.app.dns.fakedns.FakeDnsPoolMulti
+	1,  // 29: v2ray.core.app.dns.SimplifiedNameServer.query_strategy:type_name -> v2ray.core.app.dns.QueryStrategy
+	2,  // 30: v2ray.core.app.dns.SimplifiedNameServer.cache_strategy:type_name -> v2ray.core.app.dns.CacheStrategy
+	3,  // 31: v2ray.core.app.dns.SimplifiedNameServer.fallback_strategy:type_name -> v2ray.core.app.dns.FallbackStrategy
+	0,  // 32: v2ray.core.app.dns.NameServer.PriorityDomain.type:type_name -> v2ray.core.app.dns.DomainMatchingType
+	18, // 33: v2ray.core.app.dns.Config.HostsEntry.value:type_name -> v2ray.core.common.net.IPOrDomain
+	0,  // 34: v2ray.core.app.dns.SimplifiedNameServer.PriorityDomain.type:type_name -> v2ray.core.app.dns.DomainMatchingType
+	35, // [35:35] is the sub-list for method output_type
+	35, // [35:35] is the sub-list for method input_type
+	35, // [35:35] is the sub-list for extension type_name
+	35, // [35:35] is the sub-list for extension extendee
+	0,  // [0:35] is the sub-list for field type_name
 }
 }
 
 
 func init() { file_app_dns_config_proto_init() }
 func init() { file_app_dns_config_proto_init() }

+ 13 - 0
app/dns/config.proto

@@ -9,6 +9,7 @@ option java_multiple_files = true;
 import "common/net/address.proto";
 import "common/net/address.proto";
 import "common/net/destination.proto";
 import "common/net/destination.proto";
 import "app/router/routercommon/common.proto";
 import "app/router/routercommon/common.proto";
+import "app/dns/fakedns/fakedns.proto";
 
 
 import "common/protoext/extensions.proto";
 import "common/protoext/extensions.proto";
 
 
@@ -31,6 +32,8 @@ message NameServer {
   repeated v2ray.core.app.router.routercommon.GeoIP geoip = 3;
   repeated v2ray.core.app.router.routercommon.GeoIP geoip = 3;
   repeated OriginalRule original_rules = 4;
   repeated OriginalRule original_rules = 4;
 
 
+  v2ray.core.app.dns.fakedns.FakeDnsPoolMulti fake_dns = 11;
+
   // Deprecated. Use fallback_strategy.
   // Deprecated. Use fallback_strategy.
   bool skipFallback = 6 [deprecated = true];
   bool skipFallback = 6 [deprecated = true];
 
 
@@ -91,8 +94,12 @@ message Config {
   // (IPv6).
   // (IPv6).
   bytes client_ip = 3;
   bytes client_ip = 3;
 
 
+  // Static domain-ip mapping in DNS server.
   repeated HostMapping static_hosts = 4;
   repeated HostMapping static_hosts = 4;
 
 
+  // Global fakedns object.
+  v2ray.core.app.dns.fakedns.FakeDnsPoolMulti fake_dns = 16;
+
   // Tag is the inbound tag of DNS client.
   // Tag is the inbound tag of DNS client.
   string tag = 6;
   string tag = 6;
 
 
@@ -143,8 +150,12 @@ message SimplifiedConfig {
   // (IPv6).
   // (IPv6).
   string client_ip = 3;
   string client_ip = 3;
 
 
+  // Static domain-ip mapping in DNS server.
   repeated HostMapping static_hosts = 4;
   repeated HostMapping static_hosts = 4;
 
 
+  // Global fakedns object.
+  v2ray.core.app.dns.fakedns.FakeDnsPoolMulti fake_dns = 16;
+
   // Tag is the inbound tag of DNS client.
   // Tag is the inbound tag of DNS client.
   string tag = 6;
   string tag = 6;
 
 
@@ -204,6 +215,8 @@ message SimplifiedNameServer {
   repeated v2ray.core.app.router.routercommon.GeoIP geoip = 3;
   repeated v2ray.core.app.router.routercommon.GeoIP geoip = 3;
   repeated OriginalRule original_rules = 4;
   repeated OriginalRule original_rules = 4;
 
 
+  v2ray.core.app.dns.fakedns.FakeDnsPoolMulti fake_dns = 11;
+
   // Deprecated. Use fallback_strategy.
   // Deprecated. Use fallback_strategy.
   bool skipFallback = 6 [deprecated = true];
   bool skipFallback = 6 [deprecated = true];
 
 

+ 115 - 57
app/dns/dns.go

@@ -12,6 +12,8 @@ import (
 	"strings"
 	"strings"
 	"sync"
 	"sync"
 
 
+	core "github.com/v2fly/v2ray-core/v5"
+	"github.com/v2fly/v2ray-core/v5/app/dns/fakedns"
 	"github.com/v2fly/v2ray-core/v5/app/router"
 	"github.com/v2fly/v2ray-core/v5/app/router"
 	"github.com/v2fly/v2ray-core/v5/common"
 	"github.com/v2fly/v2ray-core/v5/common"
 	"github.com/v2fly/v2ray-core/v5/common/errors"
 	"github.com/v2fly/v2ray-core/v5/common/errors"
@@ -28,11 +30,11 @@ import (
 // DNS is a DNS rely server.
 // DNS is a DNS rely server.
 type DNS struct {
 type DNS struct {
 	sync.Mutex
 	sync.Mutex
-	ipOption      dns.IPOption
 	hosts         *StaticHosts
 	hosts         *StaticHosts
 	clients       []*Client
 	clients       []*Client
 	ctx           context.Context
 	ctx           context.Context
 	clientTags    map[string]bool
 	clientTags    map[string]bool
+	fakeDNSEngine *FakeDNSEngine
 	domainMatcher strmatcher.IndexMatcher
 	domainMatcher strmatcher.IndexMatcher
 	matcherInfos  []DomainMatcherInfo
 	matcherInfos  []DomainMatcherInfo
 }
 }
@@ -78,31 +80,31 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
 		clients = append(clients, NewLocalDNSClient())
 		clients = append(clients, NewLocalDNSClient())
 	}
 	}
 
 
+	s := &DNS{
+		hosts:   hosts,
+		clients: clients,
+		ctx:     ctx,
+	}
+
 	// Establish members related to global DNS state
 	// Establish members related to global DNS state
-	domainMatcher, matcherInfos, err := establishDomainRules(config, clients, nsClientMap)
-	if err != nil {
+	s.clientTags = make(map[string]bool)
+	for _, client := range clients {
+		s.clientTags[client.tag] = true
+	}
+	if err := establishDomainRules(s, config, nsClientMap); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	if err := establishExpectedIPs(config, clients, nsClientMap); err != nil {
+	if err := establishExpectedIPs(s, config, nsClientMap); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	clientTags := make(map[string]bool)
-	for _, client := range clients {
-		clientTags[client.tag] = true
+	if err := establishFakeDNS(s, config, nsClientMap); err != nil {
+		return nil, err
 	}
 	}
 
 
-	return &DNS{
-		ipOption:      toIPOption(config.QueryStrategy),
-		hosts:         hosts,
-		clients:       clients,
-		ctx:           ctx,
-		clientTags:    clientTags,
-		domainMatcher: domainMatcher,
-		matcherInfos:  matcherInfos,
-	}, nil
+	return s, nil
 }
 }
 
 
-func establishDomainRules(config *Config, clients []*Client, nsClientMap map[int]int) (strmatcher.IndexMatcher, []DomainMatcherInfo, error) {
+func establishDomainRules(s *DNS, config *Config, nsClientMap map[int]int) error {
 	domainRuleCount := 0
 	domainRuleCount := 0
 	for _, ns := range config.NameServer {
 	for _, ns := range config.NameServer {
 		domainRuleCount += len(ns.PrioritizedDomain)
 		domainRuleCount += len(ns.PrioritizedDomain)
@@ -128,7 +130,7 @@ func establishDomainRules(config *Config, clients []*Client, nsClientMap map[int
 		for _, domain := range ns.PrioritizedDomain {
 		for _, domain := range ns.PrioritizedDomain {
 			domainRule, err := toStrMatcher(domain.Type, domain.Domain)
 			domainRule, err := toStrMatcher(domain.Type, domain.Domain)
 			if err != nil {
 			if err != nil {
-				return nil, nil, newError("failed to create prioritized domain").Base(err).AtWarning()
+				return newError("failed to create prioritized domain").Base(err).AtWarning()
 			}
 			}
 			originalRuleIdx := ruleCurr
 			originalRuleIdx := ruleCurr
 			if ruleCurr < len(ns.OriginalRules) {
 			if ruleCurr < len(ns.OriginalRules) {
@@ -151,18 +153,20 @@ func establishDomainRules(config *Config, clients []*Client, nsClientMap map[int
 				domainRuleIdx: uint16(originalRuleIdx),
 				domainRuleIdx: uint16(originalRuleIdx),
 			}
 			}
 			if err != nil {
 			if err != nil {
-				return nil, nil, newError("failed to create prioritized domain").Base(err).AtWarning()
+				return newError("failed to create prioritized domain").Base(err).AtWarning()
 			}
 			}
 		}
 		}
-		clients[clientIdx].domains = rules
+		s.clients[clientIdx].domains = rules
 	}
 	}
 	if err := domainMatcher.Build(); err != nil {
 	if err := domainMatcher.Build(); err != nil {
-		return nil, nil, err
+		return err
 	}
 	}
-	return domainMatcher, matcherInfos, nil
+	s.domainMatcher = domainMatcher
+	s.matcherInfos = matcherInfos
+	return nil
 }
 }
 
 
-func establishExpectedIPs(config *Config, clients []*Client, nsClientMap map[int]int) error {
+func establishExpectedIPs(s *DNS, config *Config, nsClientMap map[int]int) error {
 	geoipContainer := router.GeoIPMatcherContainer{}
 	geoipContainer := router.GeoIPMatcherContainer{}
 	for nsIdx, ns := range config.NameServer {
 	for nsIdx, ns := range config.NameServer {
 		clientIdx := nsClientMap[nsIdx]
 		clientIdx := nsClientMap[nsIdx]
@@ -174,11 +178,51 @@ func establishExpectedIPs(config *Config, clients []*Client, nsClientMap map[int
 			}
 			}
 			matchers = append(matchers, matcher)
 			matchers = append(matchers, matcher)
 		}
 		}
-		clients[clientIdx].expectIPs = matchers
+		s.clients[clientIdx].expectIPs = matchers
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
+func establishFakeDNS(s *DNS, config *Config, nsClientMap map[int]int) error {
+	fakeHolders := &fakedns.HolderMulti{}
+	fakeDefault := (*fakedns.HolderMulti)(nil)
+	if config.FakeDns != nil {
+		defaultEngine, err := fakeHolders.AddPoolMulti(config.FakeDns)
+		if err != nil {
+			return newError("fail to create fake dns").Base(err).AtWarning()
+		}
+		fakeDefault = defaultEngine
+	}
+	for nsIdx, ns := range config.NameServer {
+		clientIdx := nsClientMap[nsIdx]
+		if ns.FakeDns == nil {
+			continue
+		}
+		engine, err := fakeHolders.AddPoolMulti(ns.FakeDns)
+		if err != nil {
+			return newError("fail to create fake dns").Base(err).AtWarning()
+		}
+		s.clients[clientIdx].fakeDNS = NewFakeDNSServer(engine)
+		s.clients[clientIdx].queryStrategy.FakeEnable = true
+	}
+	// Do not create FakeDNSEngine feature if no FakeDNS server is configured
+	if fakeHolders.IsEmpty() {
+		return nil
+	}
+	// Add FakeDNSEngine feature when DNS feature is added for the first time
+	s.fakeDNSEngine = &FakeDNSEngine{dns: s, fakeHolders: fakeHolders, fakeDefault: fakeDefault}
+	return core.RequireFeatures(s.ctx, func(client dns.Client) error {
+		v := core.MustFromContext(s.ctx)
+		if v.GetFeature(dns.FakeDNSEngineType()) != nil {
+			return nil
+		}
+		if client, ok := client.(dns.ClientWithFakeDNS); ok {
+			return v.AddFeature(client.AsFakeDNSEngine())
+		}
+		return nil
+	})
+}
+
 // Type implements common.HasType.
 // Type implements common.HasType.
 func (*DNS) Type() interface{} {
 func (*DNS) Type() interface{} {
 	return dns.ClientType()
 	return dns.ClientType()
@@ -200,25 +244,29 @@ func (s *DNS) IsOwnLink(ctx context.Context) bool {
 	return inbound != nil && s.clientTags[inbound.Tag]
 	return inbound != nil && s.clientTags[inbound.Tag]
 }
 }
 
 
+// AsFakeDNSClient implements dns.ClientWithFakeDNS.
+func (s *DNS) AsFakeDNSClient() dns.Client {
+	return &FakeDNSClient{DNS: s}
+}
+
+// AsFakeDNSEngine implements dns.ClientWithFakeDNS.
+func (s *DNS) AsFakeDNSEngine() dns.FakeDNSEngine {
+	return s.fakeDNSEngine
+}
+
 // LookupIP implements dns.Client.
 // LookupIP implements dns.Client.
 func (s *DNS) LookupIP(domain string) ([]net.IP, error) {
 func (s *DNS) LookupIP(domain string) ([]net.IP, error) {
-	return s.lookupIPInternal(domain, s.ipOption)
+	return s.lookupIPInternal(domain, dns.IPOption{IPv4Enable: true, IPv6Enable: true, FakeEnable: false})
 }
 }
 
 
 // LookupIPv4 implements dns.IPv4Lookup.
 // LookupIPv4 implements dns.IPv4Lookup.
 func (s *DNS) LookupIPv4(domain string) ([]net.IP, error) {
 func (s *DNS) LookupIPv4(domain string) ([]net.IP, error) {
-	if option := s.ipOption.With(dns.IPOption{IPv4Enable: true}); option.IsValid() {
-		return s.lookupIPInternal(domain, option)
-	}
-	return nil, dns.ErrEmptyResponse
+	return s.lookupIPInternal(domain, dns.IPOption{IPv4Enable: true, FakeEnable: false})
 }
 }
 
 
 // LookupIPv6 implements dns.IPv6Lookup.
 // LookupIPv6 implements dns.IPv6Lookup.
 func (s *DNS) LookupIPv6(domain string) ([]net.IP, error) {
 func (s *DNS) LookupIPv6(domain string) ([]net.IP, error) {
-	if option := s.ipOption.With(dns.IPOption{IPv6Enable: true}); option.IsValid() {
-		return s.lookupIPInternal(domain, option)
-	}
-	return nil, dns.ErrEmptyResponse
+	return s.lookupIPInternal(domain, dns.IPOption{IPv6Enable: true, FakeEnable: false})
 }
 }
 
 
 func (s *DNS) lookupIPInternal(domain string, option dns.IPOption) ([]net.IP, error) {
 func (s *DNS) lookupIPInternal(domain string, option dns.IPOption) ([]net.IP, error) {
@@ -257,33 +305,20 @@ func (s *DNS) lookupIPInternal(domain string, option dns.IPOption) ([]net.IP, er
 			newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog()
 			newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog()
 		}
 		}
 		if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch {
 		if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch {
-			return nil, err // Continues lookup for certain errors
+			return nil, err // Only continue lookup for certain errors
 		}
 		}
 	}
 	}
 
 
+	if len(errs) == 0 {
+		return nil, dns.ErrEmptyResponse
+	}
 	return nil, newError("returning nil for domain ", domain).Base(errors.Combine(errs...))
 	return nil, newError("returning nil for domain ", domain).Base(errors.Combine(errs...))
 }
 }
 
 
-// GetIPOption implements ClientWithIPOption.
-func (s *DNS) GetIPOption() *dns.IPOption {
-	return &s.ipOption
-}
-
-// SetQueryOption implements ClientWithIPOption.
-func (s *DNS) SetQueryOption(isIPv4Enable, isIPv6Enable bool) {
-	s.ipOption.IPv4Enable = isIPv4Enable
-	s.ipOption.IPv6Enable = isIPv6Enable
-}
-
-// SetFakeDNSOption implements ClientWithIPOption.
-func (s *DNS) SetFakeDNSOption(isFakeEnable bool) {
-	s.ipOption.FakeEnable = isFakeEnable
-}
-
 func (s *DNS) sortClients(domain string, option dns.IPOption) []*Client {
 func (s *DNS) sortClients(domain string, option dns.IPOption) []*Client {
 	clients := make([]*Client, 0, len(s.clients))
 	clients := make([]*Client, 0, len(s.clients))
 	clientUsed := make([]bool, len(s.clients))
 	clientUsed := make([]bool, len(s.clients))
-	clientNames := make([]string, 0, len(s.clients))
+	clientIdxs := make([]int, 0, len(s.clients))
 	domainRules := []string{}
 	domainRules := []string{}
 
 
 	// Priority domain matching
 	// Priority domain matching
@@ -295,12 +330,12 @@ func (s *DNS) sortClients(domain string, option dns.IPOption) []*Client {
 		switch {
 		switch {
 		case clientUsed[info.clientIdx]:
 		case clientUsed[info.clientIdx]:
 			continue
 			continue
-		case !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS"):
+		case !option.FakeEnable && isFakeDNS(client.server):
 			continue
 			continue
 		}
 		}
 		clientUsed[info.clientIdx] = true
 		clientUsed[info.clientIdx] = true
 		clients = append(clients, client)
 		clients = append(clients, client)
-		clientNames = append(clientNames, client.Name())
+		clientIdxs = append(clientIdxs, int(info.clientIdx))
 	}
 	}
 
 
 	// Default round-robin query
 	// Default round-robin query
@@ -309,7 +344,7 @@ func (s *DNS) sortClients(domain string, option dns.IPOption) []*Client {
 		switch {
 		switch {
 		case clientUsed[idx]:
 		case clientUsed[idx]:
 			continue
 			continue
-		case !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS"):
+		case !option.FakeEnable && isFakeDNS(client.server):
 			continue
 			continue
 		case client.fallbackStrategy == FallbackStrategy_Disabled:
 		case client.fallbackStrategy == FallbackStrategy_Disabled:
 			continue
 			continue
@@ -318,19 +353,42 @@ func (s *DNS) sortClients(domain string, option dns.IPOption) []*Client {
 		}
 		}
 		clientUsed[idx] = true
 		clientUsed[idx] = true
 		clients = append(clients, client)
 		clients = append(clients, client)
-		clientNames = append(clientNames, client.Name())
+		clientIdxs = append(clientIdxs, idx)
 	}
 	}
 
 
 	if len(domainRules) > 0 {
 	if len(domainRules) > 0 {
 		newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog()
 		newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog()
 	}
 	}
-	if len(clientNames) > 0 {
-		newError("domain ", domain, " will use DNS in order: ", clientNames, " ", toReqTypes(option)).AtDebug().WriteToLog()
+	if len(clientIdxs) > 0 {
+		newError("domain ", domain, " will use DNS in order: ", s.formatClientNames(clientIdxs, option), " ", toReqTypes(option)).AtDebug().WriteToLog()
 	}
 	}
 
 
 	return clients
 	return clients
 }
 }
 
 
+func (s *DNS) formatClientNames(clientIdxs []int, option dns.IPOption) []string {
+	clientNames := make([]string, 0, len(clientIdxs))
+	counter := make(map[string]uint, len(clientIdxs))
+	for _, clientIdx := range clientIdxs {
+		client := s.clients[clientIdx]
+		var name string
+		if option.With(client.queryStrategy).FakeEnable {
+			name = fmt.Sprintf("%s(DNS idx:%d)", client.fakeDNS.Name(), clientIdx)
+		} else {
+			name = client.Name()
+		}
+		counter[name]++
+		clientNames = append(clientNames, name)
+	}
+	for idx, clientIdx := range clientIdxs {
+		name := clientNames[idx]
+		if counter[name] > 1 {
+			clientNames[idx] = fmt.Sprintf("%s(DNS idx:%d)", name, clientIdx)
+		}
+	}
+	return clientNames
+}
+
 func init() {
 func init() {
 	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
 	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
 		return New(ctx, config.(*Config))
 		return New(ctx, config.(*Config))

+ 10 - 0
app/dns/dnscommon.go

@@ -226,3 +226,13 @@ L:
 
 
 	return ipRecord, nil
 	return ipRecord, nil
 }
 }
+
+func filterIP(ips []net.Address, option dns_feature.IPOption) []net.Address {
+	filtered := make([]net.Address, 0, len(ips))
+	for _, ip := range ips {
+		if (ip.Family().IsIPv4() && option.IPv4Enable) || (ip.Family().IsIPv6() && option.IPv6Enable) {
+			filtered = append(filtered, ip)
+		}
+	}
+	return filtered
+}

+ 87 - 0
app/dns/fakedns.go

@@ -0,0 +1,87 @@
+//go:build !confonly
+// +build !confonly
+
+package dns
+
+import (
+	fakedns "github.com/v2fly/v2ray-core/v5/app/dns/fakedns"
+	"github.com/v2fly/v2ray-core/v5/common/net"
+	"github.com/v2fly/v2ray-core/v5/features/dns"
+)
+
+// FakeDNSClient is an implementation of dns.Client with FakeDNS enabled.
+type FakeDNSClient struct {
+	*DNS
+}
+
+// LookupIP implements dns.Client.
+func (s *FakeDNSClient) LookupIP(domain string) ([]net.IP, error) {
+	return s.lookupIPInternal(domain, dns.IPOption{IPv4Enable: true, IPv6Enable: true, FakeEnable: true})
+}
+
+// LookupIPv4 implements dns.IPv4Lookup.
+func (s *FakeDNSClient) LookupIPv4(domain string) ([]net.IP, error) {
+	return s.lookupIPInternal(domain, dns.IPOption{IPv4Enable: true, FakeEnable: true})
+}
+
+// LookupIPv6 implements dns.IPv6Lookup.
+func (s *FakeDNSClient) LookupIPv6(domain string) ([]net.IP, error) {
+	return s.lookupIPInternal(domain, dns.IPOption{IPv6Enable: true, FakeEnable: true})
+}
+
+// FakeDNSEngine is an implementation of dns.FakeDNSEngine based on a fully functional DNS.
+type FakeDNSEngine struct {
+	dns         *DNS
+	fakeHolders *fakedns.HolderMulti
+	fakeDefault *fakedns.HolderMulti
+}
+
+// Type implements common.HasType.
+func (*FakeDNSEngine) Type() interface{} {
+	return dns.FakeDNSEngineType()
+}
+
+// Start implements common.Runnable.
+func (f *FakeDNSEngine) Start() error {
+	return f.fakeHolders.Start()
+}
+
+// Close implements common.Closable.
+func (f *FakeDNSEngine) Close() error {
+	return f.fakeHolders.Close()
+}
+
+// GetFakeIPForDomain implements dns.FakeDNSEngine.
+func (f *FakeDNSEngine) GetFakeIPForDomain(domain string) []net.Address {
+	return f.GetFakeIPForDomain3(domain, true, true)
+}
+
+// GetDomainFromFakeDNS implements dns.FakeDNSEngine.
+func (f *FakeDNSEngine) GetDomainFromFakeDNS(ip net.Address) string {
+	return f.fakeHolders.GetDomainFromFakeDNS(ip)
+}
+
+// IsIPInIPPool implements dns.FakeDNSEngineRev0.
+func (f *FakeDNSEngine) IsIPInIPPool(ip net.Address) bool {
+	return f.fakeHolders.IsIPInIPPool(ip)
+}
+
+// GetFakeIPForDomain3 implements dns.FakeDNSEngineRev0.
+func (f *FakeDNSEngine) GetFakeIPForDomain3(domain string, IPv4 bool, IPv6 bool) []net.Address { // nolint: gocritic
+	option := dns.IPOption{IPv4Enable: IPv4, IPv6Enable: IPv6, FakeEnable: true}
+	for _, client := range f.dns.sortClients(domain, option) {
+		fakeServer, ok := client.fakeDNS.(*FakeDNSServer)
+		if !ok {
+			continue
+		}
+		fakeEngine, ok := fakeServer.fakeDNSEngine.(dns.FakeDNSEngineRev0)
+		if !ok {
+			return filterIP(fakeServer.fakeDNSEngine.GetFakeIPForDomain(domain), option)
+		}
+		return fakeEngine.GetFakeIPForDomain3(domain, IPv4, IPv6)
+	}
+	if f.fakeDefault != nil {
+		return f.fakeDefault.GetFakeIPForDomain3(domain, IPv4, IPv6)
+	}
+	return nil
+}

+ 62 - 16
app/dns/fakedns/fake.go

@@ -42,7 +42,7 @@ func (fkdns *Holder) GetFakeIPForDomain3(domain string, ipv4, ipv6 bool) []net.A
 }
 }
 
 
 func (*Holder) Type() interface{} {
 func (*Holder) Type() interface{} {
-	return (*dns.FakeDNSEngine)(nil)
+	return dns.FakeDNSEngineType()
 }
 }
 
 
 func (fkdns *Holder) Start() error {
 func (fkdns *Holder) Start() error {
@@ -147,8 +147,6 @@ func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
 
 
 type HolderMulti struct {
 type HolderMulti struct {
 	holders []*Holder
 	holders []*Holder
-
-	config *FakeDnsPoolMulti
 }
 }
 
 
 func (h *HolderMulti) IsIPInIPPool(ip net.Address) bool {
 func (h *HolderMulti) IsIPInIPPool(ip net.Address) bool {
@@ -188,18 +186,67 @@ func (h *HolderMulti) GetDomainFromFakeDNS(ip net.Address) string {
 	return ""
 	return ""
 }
 }
 
 
+func (h *HolderMulti) IsEmpty() bool {
+	return len(h.holders) == 0
+}
+
+func (h *HolderMulti) AddPool(poolConfig *FakeDnsPool) (*Holder, error) {
+	_, newIPRange, err := gonet.ParseCIDR(poolConfig.IpPool)
+	if err != nil {
+		return nil, err
+	}
+	running := false
+	for _, v := range h.holders {
+		var ipRange *gonet.IPNet
+		if v.ipRange != nil {
+			ipRange = v.ipRange
+			running = true
+		} else {
+			_, ipRange, err = gonet.ParseCIDR(v.config.IpPool)
+			if err != nil {
+				return nil, err
+			}
+		}
+		if ipRange.String() == newIPRange.String() {
+			return v, nil
+		}
+		if ipRange.Contains(newIPRange.IP) || newIPRange.Contains(ipRange.IP) {
+			return nil, newError("Trying to add ip pool ", newIPRange, " that overlaps with existing ip pool ", ipRange)
+		}
+	}
+	holder, err := NewFakeDNSHolderConfigOnly(poolConfig)
+	if err != nil {
+		return nil, err
+	}
+	if running {
+		if err := holder.Start(); err != nil {
+			return nil, err
+		}
+	}
+	h.holders = append(h.holders, holder)
+	return holder, nil
+}
+
+func (h *HolderMulti) AddPoolMulti(poolMultiConfig *FakeDnsPoolMulti) (*HolderMulti, error) {
+	holderMulti := &HolderMulti{}
+	for _, poolConfig := range poolMultiConfig.Pools {
+		pool, err := h.AddPool(poolConfig)
+		if err != nil {
+			return nil, err
+		}
+		holderMulti.holders = append(holderMulti.holders, pool)
+	}
+	return holderMulti, nil // Returned holderMulti holds references to pools managed by `h`
+}
+
 func (h *HolderMulti) Type() interface{} {
 func (h *HolderMulti) Type() interface{} {
-	return (*dns.FakeDNSEngine)(nil)
+	return dns.FakeDNSEngineType()
 }
 }
 
 
 func (h *HolderMulti) Start() error {
 func (h *HolderMulti) Start() error {
 	for _, v := range h.holders {
 	for _, v := range h.holders {
-		if v.config != nil && v.config.IpPool != "" && v.config.LruSize != 0 {
-			if err := v.Start(); err != nil {
-				return newError("Cannot start all fake dns pools").Base(err)
-			}
-		} else {
-			return newError("invalid fakeDNS setting")
+		if err := v.Start(); err != nil {
+			return newError("Cannot start all fake dns pools").Base(err)
 		}
 		}
 	}
 	}
 	return nil
 	return nil
@@ -214,20 +261,19 @@ func (h *HolderMulti) Close() error {
 	return nil
 	return nil
 }
 }
 
 
-func (h *HolderMulti) createHolderGroups() error {
-	for _, v := range h.config.Pools {
-		holder, err := NewFakeDNSHolderConfigOnly(v)
+func (h *HolderMulti) createHolderGroups(conf *FakeDnsPoolMulti) error {
+	for _, pool := range conf.Pools {
+		_, err := h.AddPool(pool)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		h.holders = append(h.holders, holder)
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
 func NewFakeDNSHolderMulti(conf *FakeDnsPoolMulti) (*HolderMulti, error) {
 func NewFakeDNSHolderMulti(conf *FakeDnsPoolMulti) (*HolderMulti, error) {
-	holderMulti := &HolderMulti{nil, conf}
-	if err := holderMulti.createHolderGroups(); err != nil {
+	holderMulti := &HolderMulti{}
+	if err := holderMulti.createHolderGroups(conf); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	return holderMulti, nil
 	return holderMulti, nil

+ 96 - 0
app/dns/fakedns/fakedns_test.go

@@ -217,3 +217,99 @@ func TestFakeDNSMulti(t *testing.T) {
 		})
 		})
 	})
 	})
 }
 }
+
+func TestFakeDNSMultiAddPool(t *testing.T) {
+	runTest := func(runTestBeforeStart bool) {
+		fakeMulti, err := NewFakeDNSHolderMulti(&FakeDnsPoolMulti{
+			Pools: []*FakeDnsPool{{
+				IpPool:  "240.0.0.0/12",
+				LruSize: 256,
+			}, {
+				IpPool:  "fddd:c5b4:ff5f:f4f0::/64",
+				LruSize: 256,
+			}},
+		})
+		common.Must(err)
+		if !runTestBeforeStart {
+			err = fakeMulti.Start()
+			common.Must(err)
+		}
+		t.Run("ipv4_return_existing", func(t *testing.T) {
+			pool, err := fakeMulti.AddPool(&FakeDnsPool{
+				IpPool:  "240.0.0.1/12",
+				LruSize: 256,
+			})
+			common.Must(err)
+			if pool != fakeMulti.holders[0] {
+				t.Error("HolderMulti.AddPool not returning same holder for existing IPv4 pool")
+			}
+		})
+		t.Run("ipv6_return_existing", func(t *testing.T) {
+			pool, err := fakeMulti.AddPool(&FakeDnsPool{
+				IpPool:  "fddd:c5b4:ff5f:f4f0::1/64",
+				LruSize: 256,
+			})
+			common.Must(err)
+			if pool != fakeMulti.holders[1] {
+				t.Error("HolderMulti.AddPool not returning same holder for existing IPv6 pool")
+			}
+		})
+		t.Run("ipv4_reject_overlap", func(t *testing.T) {
+			_, err := fakeMulti.AddPool(&FakeDnsPool{
+				IpPool:  "240.8.0.0/13",
+				LruSize: 256,
+			})
+			if err == nil {
+				t.Error("HolderMulti.AddPool not rejecting IPv4 pool that is subnet of existing ones")
+			}
+			_, err = fakeMulti.AddPool(&FakeDnsPool{
+				IpPool:  "240.0.0.0/11",
+				LruSize: 256,
+			})
+			if err == nil {
+				t.Error("HolderMulti.AddPool not rejecting IPv4 pool that contains existing ones")
+			}
+		})
+		t.Run("new_pool", func(t *testing.T) {
+			pool, err := fakeMulti.AddPool(&FakeDnsPool{
+				IpPool:  "192.168.168.0/16",
+				LruSize: 256,
+			})
+			common.Must(err)
+			if pool != fakeMulti.holders[2] {
+				t.Error("HolderMulti.AddPool not creating new holder for new IPv4 pool")
+			}
+		})
+		t.Run("add_pool_multi", func(t *testing.T) {
+			pools, err := fakeMulti.AddPoolMulti(&FakeDnsPoolMulti{
+				Pools: []*FakeDnsPool{{
+					IpPool:  "192.168.168.0/16",
+					LruSize: 256,
+				}, {
+					IpPool:  "2001:1111::/64",
+					LruSize: 256,
+				}},
+			})
+			common.Must(err)
+			if len(pools.holders) != 2 {
+				t.Error("HolderMulti.AddPoolMutli not returning holderMulti that has the same length as passed PoolMulti config")
+			}
+			if pools.holders[0] != fakeMulti.holders[2] {
+				t.Error("HolderMulti.AddPoolMulti not returning same holder for existing IPv4 pool 192.168.168.0/16")
+			}
+			if pools.holders[1] != fakeMulti.holders[3] {
+				t.Error("HolderMulti.AddPoolMulti not creating new holder for new IPv6 pool 2001:1111::/64")
+			}
+		})
+		if runTestBeforeStart {
+			err = fakeMulti.Start()
+			common.Must(err)
+		}
+	}
+	t.Run("addPoolBeforeStart", func(t *testing.T) {
+		runTest(true)
+	})
+	t.Run("addPoolAfterStart", func(t *testing.T) {
+		runTest(false)
+	})
+}

+ 249 - 0
app/dns/fakedns_test.go

@@ -0,0 +1,249 @@
+package dns_test
+
+import (
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/miekg/dns"
+	"google.golang.org/protobuf/types/known/anypb"
+
+	core "github.com/v2fly/v2ray-core/v5"
+	"github.com/v2fly/v2ray-core/v5/app/dispatcher"
+	. "github.com/v2fly/v2ray-core/v5/app/dns"
+	"github.com/v2fly/v2ray-core/v5/app/dns/fakedns"
+	"github.com/v2fly/v2ray-core/v5/app/policy"
+	"github.com/v2fly/v2ray-core/v5/app/proxyman"
+	"github.com/v2fly/v2ray-core/v5/common"
+	"github.com/v2fly/v2ray-core/v5/common/net"
+	"github.com/v2fly/v2ray-core/v5/common/serial"
+	feature_dns "github.com/v2fly/v2ray-core/v5/features/dns"
+	"github.com/v2fly/v2ray-core/v5/proxy/freedom"
+	"github.com/v2fly/v2ray-core/v5/testing/servers/udp"
+)
+
+func TestFakeDNS(t *testing.T) {
+	port := udp.PickPort()
+
+	dnsServer := dns.Server{
+		Addr:    "127.0.0.1:" + port.String(),
+		Net:     "udp",
+		Handler: &staticHandler{},
+		UDPSize: 1200,
+	}
+
+	go dnsServer.ListenAndServe()
+	time.Sleep(time.Second)
+
+	config := &core.Config{
+		App: []*anypb.Any{
+			serial.ToTypedMessage(&Config{
+				NameServer: []*NameServer{
+					{ // "fakedns"
+						Address: &net.Endpoint{
+							Network: net.Network_UDP,
+							Address: &net.IPOrDomain{
+								Address: &net.IPOrDomain_Domain{
+									Domain: "fakedns",
+								},
+							},
+							Port: uint32(53),
+						},
+					},
+					{ // { "address": "127.0.0.1", "port": "<port>", "domains": ["domain:google.com"], "fakedns": "198.19.0.0/16", "fallbackStrategy": "disabled" }
+						Address: &net.Endpoint{
+							Network: net.Network_UDP,
+							Address: &net.IPOrDomain{
+								Address: &net.IPOrDomain_Ip{
+									Ip: []byte{127, 0, 0, 1},
+								},
+							},
+							Port: uint32(port),
+						},
+						PrioritizedDomain: []*NameServer_PriorityDomain{
+							{Type: DomainMatchingType_Subdomain, Domain: "google.com"},
+						},
+						FakeDns: &fakedns.FakeDnsPoolMulti{
+							Pools: []*fakedns.FakeDnsPool{
+								{IpPool: "198.19.0.0/16", LruSize: 256},
+							},
+						},
+						FallbackStrategy: FallbackStrategy_Disabled.Enum(),
+					},
+				},
+				FakeDns: &fakedns.FakeDnsPoolMulti{ // "fakedns": "198.18.0.0/16"
+					Pools: []*fakedns.FakeDnsPool{
+						{IpPool: "198.18.0.0/16", LruSize: 256},
+					},
+				},
+			}),
+			serial.ToTypedMessage(&dispatcher.Config{}),
+			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
+			serial.ToTypedMessage(&policy.Config{}),
+		},
+		Outbound: []*core.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
+			},
+		},
+	}
+
+	v, err := core.New(config)
+	common.Must(err)
+	common.Must(v.Start())
+
+	dnsClient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
+	fakeClient := dnsClient.(feature_dns.ClientWithFakeDNS).AsFakeDNSClient()
+
+	var fakeIPForFacebook net.IP
+	var fakeIPForGoogle net.IP
+
+	{ // Lookup facebook.com with Fake Client will return 198.18.0.0/16 (global fake pool)
+		ips, err := fakeClient.LookupIP("facebook.com")
+		if err != nil {
+			t.Fatal("unexpected error: ", err)
+		}
+		for _, ip := range ips {
+			if !(&net.IPNet{IP: net.IP{198, 18, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip) {
+				t.Fatal("Lookup facebook.com with fake client not in global pool 198.18.0.0/16")
+			}
+		}
+		fakeIPForFacebook = ips[0]
+	}
+	{ // Lookup facebook.com with Normal Client with return empty record (because UDP server matching "domain:google.com" are configured with fallback disabled)
+		_, err := dnsClient.LookupIP("facebook.com")
+		if err != feature_dns.ErrEmptyResponse {
+			t.Fatal("Lookup facebook.com with normal client not returning empty response")
+		}
+	}
+	{ // Lookup google.com with Fake Client will return 198.19.0.0/16 (local fake pool)
+		ips, err := fakeClient.LookupIP("google.com")
+		if err != nil {
+			t.Fatal("unexpected error: ", err)
+		}
+		for _, ip := range ips {
+			if !(&net.IPNet{IP: net.IP{198, 19, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip) {
+				t.Fatal("Lookup google.com with fake client not in global pool 198.19.0.0/16")
+			}
+		}
+		fakeIPForGoogle = ips[0]
+	}
+	{ // Lookup google.com with Normal Client will return 8.8.8.8
+		ips, err := dnsClient.LookupIP("google.com")
+		if err != nil {
+			t.Fatal("unexpected error: ", err)
+		}
+		if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
+			t.Fatal("Lookup google.com with normal client not returning 8.8.8.8")
+		}
+	}
+
+	fakeEngine := dnsClient.(feature_dns.ClientWithFakeDNS).AsFakeDNSEngine().(feature_dns.FakeDNSEngineRev0)
+	{
+		if !fakeEngine.IsIPInIPPool(net.IPAddress(fakeIPForFacebook)) {
+			t.Fatal("Fake IP of domain facebook.com not in FakeDNSEngine's pool.")
+		}
+		if !fakeEngine.IsIPInIPPool(net.IPAddress(fakeIPForGoogle)) {
+			t.Fatal("Fake IP of domain google.com not in FakeDNSEngine's pool.")
+		}
+	}
+	{
+		if domain := fakeEngine.GetDomainFromFakeDNS(net.IPAddress(fakeIPForFacebook)); domain != "facebook.com" {
+			t.Fatal("Recover fake IP to get domain facebook.com failed.")
+		}
+		if domain := fakeEngine.GetDomainFromFakeDNS(net.IPAddress(fakeIPForGoogle)); domain != "google.com" {
+			t.Fatal("Recover fake IP to get domain google.com failed.")
+		}
+	}
+	{
+		ips := fakeEngine.GetFakeIPForDomain("api.google.com")
+		for _, ip := range ips {
+			if !(&net.IPNet{IP: net.IP{198, 19, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip.IP()) {
+				t.Fatal("Fake IP for api.google.com not in local pool 198.19.0.0/16")
+			}
+		}
+	}
+	{
+		ips := fakeEngine.GetFakeIPForDomain3("v2fly.org", true, false)
+		for _, ip := range ips {
+			if !(&net.IPNet{IP: net.IP{198, 18, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip.IP()) {
+				t.Fatal("Fake IP for v2fly.org not in global pool 198.18.0.0/16")
+			}
+		}
+	}
+}
+
+func TestFakeDNSEmptyGlobalConfig(t *testing.T) {
+	config := &core.Config{
+		App: []*anypb.Any{
+			serial.ToTypedMessage(&Config{
+				NameServer: []*NameServer{
+					{ // "fakedns"
+						Address: &net.Endpoint{
+							Network: net.Network_UDP,
+							Address: &net.IPOrDomain{
+								Address: &net.IPOrDomain_Domain{
+									Domain: "fakedns",
+								},
+							},
+						},
+						QueryStrategy: QueryStrategy_USE_IP4.Enum(),
+					},
+					{ // "localhost"
+						Address: &net.Endpoint{
+							Network: net.Network_UDP,
+							Address: &net.IPOrDomain{
+								Address: &net.IPOrDomain_Domain{
+									Domain: "localhost",
+								},
+							},
+						},
+						QueryStrategy: QueryStrategy_USE_IP6.Enum(),
+						PrioritizedDomain: []*NameServer_PriorityDomain{
+							{Type: DomainMatchingType_Subdomain, Domain: "google.com"},
+						},
+						FakeDns: &fakedns.FakeDnsPoolMulti{Pools: []*fakedns.FakeDnsPool{}}, // "fakedns": true
+					},
+				},
+			}),
+			serial.ToTypedMessage(&dispatcher.Config{}),
+			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
+			serial.ToTypedMessage(&policy.Config{}),
+		},
+		Outbound: []*core.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
+			},
+		},
+	}
+
+	v, err := core.New(config)
+	common.Must(err)
+	common.Must(v.Start())
+
+	dnsClient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
+	fakeClient := dnsClient.(feature_dns.ClientWithFakeDNS).AsFakeDNSClient()
+
+	{ // Lookup facebook.com will return 198.18.0.0/15 (default IPv4 pool)
+		ips, err := fakeClient.LookupIP("facebook.com")
+		if err != nil {
+			t.Fatal("unexpected error: ", err)
+		}
+		for _, ip := range ips {
+			if !(&net.IPNet{IP: net.IP{198, 18, 0, 0}, Mask: net.CIDRMask(15, 8*net.IPv4len)}).Contains(ip) {
+				t.Fatal("Lookup facebook.com with fake client not in default IPv4 pool 198.18.0.0/15")
+			}
+		}
+	}
+	{ // Lookup google.com will return fc00::/18 (default IPv6 pool)
+		ips, err := fakeClient.LookupIP("google.com")
+		if err != nil {
+			t.Fatal("unexpected error: ", err)
+		}
+		for _, ip := range ips {
+			if !(&net.IPNet{IP: net.IP{0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Mask: net.CIDRMask(18, 8*net.IPv6len)}).Contains(ip) {
+				t.Fatal("Lookup google.com with fake client not in default IPv6 pool fc00::/18")
+			}
+		}
+	}
+}

+ 0 - 10
app/dns/hosts.go

@@ -67,16 +67,6 @@ func NewStaticHosts(hosts []*HostMapping, legacy map[string]*net.IPOrDomain) (*S
 	return sh, nil
 	return sh, nil
 }
 }
 
 
-func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
-	filtered := make([]net.Address, 0, len(ips))
-	for _, ip := range ips {
-		if (ip.Family().IsIPv4() && option.IPv4Enable) || (ip.Family().IsIPv6() && option.IPv6Enable) {
-			filtered = append(filtered, ip)
-		}
-	}
-	return filtered
-}
-
 func (h *StaticHosts) lookupInternal(domain string) []net.Address {
 func (h *StaticHosts) lookupInternal(domain string) []net.Address {
 	var ips []net.Address
 	var ips []net.Address
 	for _, id := range h.matchers.Match(domain) {
 	for _, id := range h.matchers.Match(domain) {

+ 50 - 22
app/dns/nameserver.go

@@ -7,6 +7,7 @@ import (
 	"time"
 	"time"
 
 
 	core "github.com/v2fly/v2ray-core/v5"
 	core "github.com/v2fly/v2ray-core/v5"
+	"github.com/v2fly/v2ray-core/v5/app/dns/fakedns"
 	"github.com/v2fly/v2ray-core/v5/app/router"
 	"github.com/v2fly/v2ray-core/v5/app/router"
 	"github.com/v2fly/v2ray-core/v5/common/errors"
 	"github.com/v2fly/v2ray-core/v5/common/errors"
 	"github.com/v2fly/v2ray-core/v5/common/net"
 	"github.com/v2fly/v2ray-core/v5/common/net"
@@ -36,41 +37,48 @@ type Client struct {
 
 
 	domains   []string
 	domains   []string
 	expectIPs []*router.GeoIPMatcher
 	expectIPs []*router.GeoIPMatcher
+	fakeDNS   Server
 }
 }
 
 
 var errExpectedIPNonMatch = errors.New("expectIPs not match")
 var errExpectedIPNonMatch = errors.New("expectIPs not match")
 
 
 // NewServer creates a name server object according to the network destination url.
 // NewServer creates a name server object according to the network destination url.
-func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, error) {
+func NewServer(ctx context.Context, dest net.Destination, onCreated func(Server) error) error {
+	onCreatedWithError := func(server Server, err error) error {
+		if err != nil {
+			return err
+		}
+		return onCreated(server)
+	}
 	if address := dest.Address; address.Family().IsDomain() {
 	if address := dest.Address; address.Family().IsDomain() {
 		u, err := url.Parse(address.Domain())
 		u, err := url.Parse(address.Domain())
 		if err != nil {
 		if err != nil {
-			return nil, err
+			return err
 		}
 		}
 		switch {
 		switch {
 		case strings.EqualFold(u.String(), "localhost"):
 		case strings.EqualFold(u.String(), "localhost"):
-			return NewLocalNameServer(), nil
+			return onCreated(NewLocalNameServer())
+		case strings.EqualFold(u.String(), "fakedns"):
+			return core.RequireFeatures(ctx, func(fakedns dns.FakeDNSEngine) error { return onCreated(NewFakeDNSServer(fakedns)) })
 		case strings.EqualFold(u.Scheme, "https"): // DOH Remote mode
 		case strings.EqualFold(u.Scheme, "https"): // DOH Remote mode
-			return NewDoHNameServer(u, dispatcher)
+			return core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error { return onCreatedWithError(NewDoHNameServer(u, dispatcher)) })
 		case strings.EqualFold(u.Scheme, "https+local"): // DOH Local mode
 		case strings.EqualFold(u.Scheme, "https+local"): // DOH Local mode
-			return NewDoHLocalNameServer(u), nil
-		case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
-			return NewQUICNameServer(u)
+			return onCreated(NewDoHLocalNameServer(u))
 		case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
 		case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
-			return NewTCPNameServer(u, dispatcher)
+			return core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error { return onCreatedWithError(NewTCPNameServer(u, dispatcher)) })
 		case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
 		case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
-			return NewTCPLocalNameServer(u)
-		case strings.EqualFold(u.String(), "fakedns"):
-			return NewFakeDNSServer(), nil
+			return onCreatedWithError(NewTCPLocalNameServer(u))
+		case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
+			return onCreatedWithError(NewQUICNameServer(u))
 		}
 		}
 	}
 	}
 	if dest.Network == net.Network_Unknown {
 	if dest.Network == net.Network_Unknown {
 		dest.Network = net.Network_UDP
 		dest.Network = net.Network_UDP
 	}
 	}
 	if dest.Network == net.Network_UDP { // UDP classic DNS mode
 	if dest.Network == net.Network_UDP { // UDP classic DNS mode
-		return NewClassicNameServer(dest, dispatcher), nil
+		return core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error { return onCreated(NewClassicNameServer(dest, dispatcher)) })
 	}
 	}
-	return nil, newError("No available name server could be created from ", dest).AtWarning()
+	return newError("No available name server could be created from ", dest).AtWarning()
 }
 }
 
 
 // NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
 // NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
@@ -78,12 +86,7 @@ func NewClient(ctx context.Context, ns *NameServer, dns *Config) (*Client, error
 	client := &Client{}
 	client := &Client{}
 
 
 	// Create DNS server instance
 	// Create DNS server instance
-	err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
-		// Create a new server for each client for now
-		server, err := NewServer(ns.Address.AsDestination(), dispatcher)
-		if err != nil {
-			return newError("failed to create nameserver").Base(err).AtWarning()
-		}
+	err := NewServer(ctx, ns.Address.AsDestination(), func(server Server) error {
 		client.server = server
 		client.server = server
 		return nil
 		return nil
 	})
 	})
@@ -130,6 +133,27 @@ func NewClient(ctx context.Context, ns *NameServer, dns *Config) (*Client, error
 			*ns.FallbackStrategy = FallbackStrategy_DisabledIfAnyMatch
 			*ns.FallbackStrategy = FallbackStrategy_DisabledIfAnyMatch
 		}
 		}
 	}
 	}
+	if (ns.FakeDns != nil && len(ns.FakeDns.Pools) == 0) || // Use globally configured fake ip pool if: 1. `fakedns` config is set, but empty(represents { "fakedns": true } in JSON settings);
+		ns.FakeDns == nil && strings.EqualFold(ns.Address.Address.GetDomain(), "fakedns") { // 2. `fakedns` config not set, but server address is `fakedns`(represents { "address": "fakedns" } in JSON settings).
+		if dns.FakeDns != nil {
+			ns.FakeDns = dns.FakeDns
+		} else {
+			ns.FakeDns = &fakedns.FakeDnsPoolMulti{}
+			queryStrategy := toIPOption(*ns.QueryStrategy)
+			if queryStrategy.IPv4Enable {
+				ns.FakeDns.Pools = append(ns.FakeDns.Pools, &fakedns.FakeDnsPool{
+					IpPool:  "198.18.0.0/15",
+					LruSize: 65535,
+				})
+			}
+			if queryStrategy.IPv6Enable {
+				ns.FakeDns.Pools = append(ns.FakeDns.Pools, &fakedns.FakeDnsPool{
+					IpPool:  "fc00::/18",
+					LruSize: 65535,
+				})
+			}
+		}
+	}
 
 
 	// Priotize local domains with specific TLDs or without any dot to local DNS
 	// Priotize local domains with specific TLDs or without any dot to local DNS
 	if strings.EqualFold(ns.Address.Address.GetDomain(), "localhost") {
 	if strings.EqualFold(ns.Address.Address.GetDomain(), "localhost") {
@@ -154,21 +178,25 @@ func (c *Client) Name() string {
 	return c.server.Name()
 	return c.server.Name()
 }
 }
 
 
-// QueryIP send DNS query to the name server with the client's IP.
+// QueryIP send DNS query to the name server with the client's IP and IP options.
 func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, error) {
 func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, error) {
 	queryOption := option.With(c.queryStrategy)
 	queryOption := option.With(c.queryStrategy)
 	if !queryOption.IsValid() {
 	if !queryOption.IsValid() {
 		newError(c.server.Name(), " returns empty answer: ", domain, ". ", toReqTypes(option)).AtInfo().WriteToLog()
 		newError(c.server.Name(), " returns empty answer: ", domain, ". ", toReqTypes(option)).AtInfo().WriteToLog()
 		return nil, dns.ErrEmptyResponse
 		return nil, dns.ErrEmptyResponse
 	}
 	}
+	server := c.server
+	if queryOption.FakeEnable && c.fakeDNS != nil {
+		server = c.fakeDNS
+	}
 	disableCache := c.cacheStrategy == CacheStrategy_CacheDisabled
 	disableCache := c.cacheStrategy == CacheStrategy_CacheDisabled
 
 
 	ctx = session.ContextWithInbound(ctx, &session.Inbound{Tag: c.tag})
 	ctx = session.ContextWithInbound(ctx, &session.Inbound{Tag: c.tag})
 	ctx, cancel := context.WithTimeout(ctx, 4*time.Second)
 	ctx, cancel := context.WithTimeout(ctx, 4*time.Second)
-	ips, err := c.server.QueryIP(ctx, domain, c.clientIP, queryOption, disableCache)
+	ips, err := server.QueryIP(ctx, domain, c.clientIP, queryOption, disableCache)
 	cancel()
 	cancel()
 
 
-	if err != nil {
+	if err != nil || queryOption.FakeEnable {
 		return ips, err
 		return ips, err
 	}
 	}
 	return c.MatchExpectedIPs(domain, ips)
 	return c.MatchExpectedIPs(domain, ips)

+ 12 - 4
app/dns/nameserver_fakedns.go

@@ -15,15 +15,18 @@ type FakeDNSServer struct {
 	fakeDNSEngine dns.FakeDNSEngine
 	fakeDNSEngine dns.FakeDNSEngine
 }
 }
 
 
-func NewFakeDNSServer() *FakeDNSServer {
-	return &FakeDNSServer{}
+func NewFakeDNSServer(fakeDNSEngine dns.FakeDNSEngine) *FakeDNSServer {
+	return &FakeDNSServer{fakeDNSEngine: fakeDNSEngine}
 }
 }
 
 
 func (FakeDNSServer) Name() string {
 func (FakeDNSServer) Name() string {
-	return "FakeDNS"
+	return "fakedns"
 }
 }
 
 
 func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, opt dns.IPOption, _ bool) ([]net.IP, error) {
 func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, opt dns.IPOption, _ bool) ([]net.IP, error) {
+	if !opt.FakeEnable {
+		return nil, nil // Returning empty ip record with no error will continue DNS lookup, effectively indicating that this server is disabled.
+	}
 	if f.fakeDNSEngine == nil {
 	if f.fakeDNSEngine == nil {
 		if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
 		if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
 			f.fakeDNSEngine = fd
 			f.fakeDNSEngine = fd
@@ -35,7 +38,7 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, op
 	if fkr0, ok := f.fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
 	if fkr0, ok := f.fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
 		ips = fkr0.GetFakeIPForDomain3(domain, opt.IPv4Enable, opt.IPv6Enable)
 		ips = fkr0.GetFakeIPForDomain3(domain, opt.IPv4Enable, opt.IPv6Enable)
 	} else {
 	} else {
-		ips = f.fakeDNSEngine.GetFakeIPForDomain(domain)
+		ips = filterIP(f.fakeDNSEngine.GetFakeIPForDomain(domain), opt)
 	}
 	}
 
 
 	netIP, err := toNetIP(ips)
 	netIP, err := toNetIP(ips)
@@ -50,3 +53,8 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, op
 	}
 	}
 	return nil, dns.ErrEmptyResponse
 	return nil, dns.ErrEmptyResponse
 }
 }
+
+func isFakeDNS(server Server) bool {
+	_, ok := server.(*FakeDNSServer)
+	return ok
+}

+ 1 - 0
common/net/system.go

@@ -19,6 +19,7 @@ var (
 	ListenUDP       = net.ListenUDP
 	ListenUDP       = net.ListenUDP
 	ListenUnix      = net.ListenUnix
 	ListenUnix      = net.ListenUnix
 	LookupIP        = net.LookupIP
 	LookupIP        = net.LookupIP
+	ParseCIDR       = net.ParseCIDR
 	ParseIP         = net.ParseIP
 	ParseIP         = net.ParseIP
 	ResolveUDPAddr  = net.ResolveUDPAddr
 	ResolveUDPAddr  = net.ResolveUDPAddr
 	ResolveUnixAddr = net.ResolveUnixAddr
 	ResolveUnixAddr = net.ResolveUnixAddr

+ 22 - 10
features/dns/client.go

@@ -50,18 +50,30 @@ type IPv6Lookup interface {
 	LookupIPv6(domain string) ([]net.IP, error)
 	LookupIPv6(domain string) ([]net.IP, error)
 }
 }
 
 
-// ClientWithIPOption is an optional feature for querying DNS information.
+// LookupIPWithOption is a helper function for querying DNS information from a dns.Client with dns.IPOption.
 //
 //
 // v2ray:api:beta
 // v2ray:api:beta
-type ClientWithIPOption interface {
-	// GetIPOption returns IPOption for the DNS client.
-	GetIPOption() *IPOption
-
-	// SetQueryOption sets IPv4Enable and IPv6Enable for the DNS client.
-	SetQueryOption(isIPv4Enable, isIPv6Enable bool)
-
-	// SetFakeDNSOption sets FakeEnable option for DNS client.
-	SetFakeDNSOption(isFakeEnable bool)
+func LookupIPWithOption(client Client, domain string, option IPOption) ([]net.IP, error) {
+	if option.FakeEnable {
+		if clientWithFakeDNS, ok := client.(ClientWithFakeDNS); ok {
+			client = clientWithFakeDNS.AsFakeDNSClient()
+		}
+	}
+	if option.IPv4Enable && !option.IPv6Enable {
+		if ipv4Lookup, ok := client.(IPv4Lookup); ok {
+			return ipv4Lookup.LookupIPv4(domain)
+		} else {
+			return nil, errors.New("dns.Client doesn't implement IPv4Lookup")
+		}
+	}
+	if option.IPv6Enable && !option.IPv4Enable {
+		if ipv6Lookup, ok := client.(IPv6Lookup); ok {
+			return ipv6Lookup.LookupIPv6(domain)
+		} else {
+			return nil, errors.New("dns.Client doesn't implement IPv6Lookup")
+		}
+	}
+	return client.LookupIP(domain)
 }
 }
 
 
 // ClientType returns the type of Client interface. Can be used for implementing common.HasType.
 // ClientType returns the type of Client interface. Can be used for implementing common.HasType.

+ 33 - 1
features/dns/fakedns.go

@@ -5,14 +5,46 @@ import (
 	"github.com/v2fly/v2ray-core/v5/features"
 	"github.com/v2fly/v2ray-core/v5/features"
 )
 )
 
 
+// FakeDNSEngine is a V2Ray feature for converting between domain and fake IPs.
+//
+// v2ray:api:beta
 type FakeDNSEngine interface {
 type FakeDNSEngine interface {
 	features.Feature
 	features.Feature
+
+	// GetFakeIPForDomain returns fake IP addresses for the given domain, and registers the domain with the returned IPs.
 	GetFakeIPForDomain(domain string) []net.Address
 	GetFakeIPForDomain(domain string) []net.Address
+
+	// GetDomainFromFakeDNS returns the bound domain name for the given fake IP.
 	GetDomainFromFakeDNS(ip net.Address) string
 	GetDomainFromFakeDNS(ip net.Address) string
 }
 }
 
 
+// FakeDNSEngineRev0 adds additional APIs for FakeDNSEngine.
+//
+// v2ray:api:beta
 type FakeDNSEngineRev0 interface {
 type FakeDNSEngineRev0 interface {
 	FakeDNSEngine
 	FakeDNSEngine
+
+	// IsIPInIPPool tests whether the given IP address resides in managed fake IP pools.
 	IsIPInIPPool(ip net.Address) bool
 	IsIPInIPPool(ip net.Address) bool
-	GetFakeIPForDomain3(domain string, IPv4, IPv6 bool) []net.Address
+
+	// GetFakeIPForDomain3 registers and returns fake IP addresses for the given domain in IPv4 and/or IPv6.
+	GetFakeIPForDomain3(domain string, IPv4 bool, IPv6 bool) []net.Address
+}
+
+// ClientWithFakeDNS is an optional feature for utilizing FakeDNS feature of DNS client.
+//
+// v2ray:api:beta
+type ClientWithFakeDNS interface {
+	// AsFakeDNSClient converts the client to dns.Client that enables FakeDNS querying option.
+	AsFakeDNSClient() Client
+
+	// AsFakeDNSEngine converts the client to dns.FakeDNSEngine that could serve FakeDNSEngine feature.
+	AsFakeDNSEngine() FakeDNSEngine
+}
+
+// FakeDNSEngineType returns the type of FakeDNSEngine interface. Can be used for implementing common.HasType.
+//
+// v2ray:api:beta
+func FakeDNSEngineType() interface{} {
+	return (*FakeDNSEngine)(nil)
 }
 }

+ 1 - 29
features/routing/dns/context.go

@@ -26,35 +26,7 @@ func (ctx *ResolvableContext) GetTargetIPs() []net.IP {
 	}
 	}
 
 
 	if domain := ctx.GetTargetDomain(); len(domain) != 0 {
 	if domain := ctx.GetTargetDomain(); len(domain) != 0 {
-		lookupFunc := ctx.dnsClient.LookupIP
-		ipOption := &dns.IPOption{
-			IPv4Enable: true,
-			IPv6Enable: true,
-		}
-
-		if c, ok := ctx.dnsClient.(dns.ClientWithIPOption); ok {
-			ipOption = c.GetIPOption()
-			c.SetFakeDNSOption(false) // Skip FakeDNS.
-		} else {
-			newError("ctx.dnsClient doesn't implement ClientWithIPOption").AtDebug().WriteToLog()
-		}
-
-		switch {
-		case ipOption.IPv4Enable && !ipOption.IPv6Enable:
-			if lookupIPv4, ok := ctx.dnsClient.(dns.IPv4Lookup); ok {
-				lookupFunc = lookupIPv4.LookupIPv4
-			} else {
-				newError("ctx.dnsClient doesn't implement IPv4Lookup. Use LookupIP instead.").AtDebug().WriteToLog()
-			}
-		case !ipOption.IPv4Enable && ipOption.IPv6Enable:
-			if lookupIPv6, ok := ctx.dnsClient.(dns.IPv6Lookup); ok {
-				lookupFunc = lookupIPv6.LookupIPv6
-			} else {
-				newError("ctx.dnsClient doesn't implement IPv6Lookup. Use LookupIP instead.").AtDebug().WriteToLog()
-			}
-		}
-
-		ips, err := lookupFunc(domain)
+		ips, err := ctx.dnsClient.LookupIP(domain)
 		if err == nil {
 		if err == nil {
 			ctx.resolvedIPs = ips
 			ctx.resolvedIPs = ips
 			return ips
 			return ips

+ 23 - 0
infra/conf/synthetic/dns/dns.go

@@ -9,6 +9,7 @@ import (
 	"strings"
 	"strings"
 
 
 	"github.com/v2fly/v2ray-core/v5/app/dns"
 	"github.com/v2fly/v2ray-core/v5/app/dns"
+	"github.com/v2fly/v2ray-core/v5/app/dns/fakedns"
 	"github.com/v2fly/v2ray-core/v5/app/router/routercommon"
 	"github.com/v2fly/v2ray-core/v5/app/router/routercommon"
 	"github.com/v2fly/v2ray-core/v5/common/net"
 	"github.com/v2fly/v2ray-core/v5/common/net"
 	"github.com/v2fly/v2ray-core/v5/common/platform"
 	"github.com/v2fly/v2ray-core/v5/common/platform"
@@ -28,6 +29,7 @@ type NameServerConfig struct {
 	SkipFallback     bool
 	SkipFallback     bool
 	Domains          []string
 	Domains          []string
 	ExpectIPs        cfgcommon.StringList
 	ExpectIPs        cfgcommon.StringList
+	FakeDNS          FakeDNSConfigExtend
 
 
 	cfgctx context.Context
 	cfgctx context.Context
 }
 }
@@ -50,6 +52,7 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
 		SkipFallback     bool                 `json:"skipFallback"`
 		SkipFallback     bool                 `json:"skipFallback"`
 		Domains          []string             `json:"domains"`
 		Domains          []string             `json:"domains"`
 		ExpectIPs        cfgcommon.StringList `json:"expectIps"`
 		ExpectIPs        cfgcommon.StringList `json:"expectIps"`
+		FakeDNS          FakeDNSConfigExtend  `json:"fakedns"`
 	}
 	}
 	if err := json.Unmarshal(data, &advanced); err == nil {
 	if err := json.Unmarshal(data, &advanced); err == nil {
 		c.Address = advanced.Address
 		c.Address = advanced.Address
@@ -62,6 +65,7 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
 		c.SkipFallback = advanced.SkipFallback
 		c.SkipFallback = advanced.SkipFallback
 		c.Domains = advanced.Domains
 		c.Domains = advanced.Domains
 		c.ExpectIPs = advanced.ExpectIPs
 		c.ExpectIPs = advanced.ExpectIPs
+		c.FakeDNS = advanced.FakeDNS
 		return nil
 		return nil
 	}
 	}
 
 
@@ -121,6 +125,15 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
 		return nil, newError("invalid IP rule: ", c.ExpectIPs).Base(err)
 		return nil, newError("invalid IP rule: ", c.ExpectIPs).Base(err)
 	}
 	}
 
 
+	var fakeDNS *fakedns.FakeDnsPoolMulti
+	if c.FakeDNS.FakeDNSConfig != nil {
+		fake, err := c.FakeDNS.FakeDNSConfig.Build()
+		if err != nil {
+			return nil, newError("failed to build fakedns").Base(err)
+		}
+		fakeDNS = fake
+	}
+
 	var myClientIP []byte
 	var myClientIP []byte
 	if c.ClientIP != nil {
 	if c.ClientIP != nil {
 		if !c.ClientIP.Family().IsIP() {
 		if !c.ClientIP.Family().IsIP() {
@@ -178,6 +191,7 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
 		PrioritizedDomain: domains,
 		PrioritizedDomain: domains,
 		Geoip:             geoipList,
 		Geoip:             geoipList,
 		OriginalRules:     originalRules,
 		OriginalRules:     originalRules,
+		FakeDns:           fakeDNS,
 	}, nil
 	}, nil
 }
 }
 
 
@@ -192,6 +206,7 @@ var typeMap = map[routercommon.Domain_Type]dns.DomainMatchingType{
 type DNSConfig struct { // nolint: revive
 type DNSConfig struct { // nolint: revive
 	Servers                []*NameServerConfig     `json:"servers"`
 	Servers                []*NameServerConfig     `json:"servers"`
 	Hosts                  map[string]*HostAddress `json:"hosts"`
 	Hosts                  map[string]*HostAddress `json:"hosts"`
+	FakeDNS                *FakeDNSConfig          `json:"fakedns"`
 	DomainMatcher          string                  `json:"domainMatcher"`
 	DomainMatcher          string                  `json:"domainMatcher"`
 	ClientIP               *cfgcommon.Address      `json:"clientIp"`
 	ClientIP               *cfgcommon.Address      `json:"clientIp"`
 	Tag                    string                  `json:"tag"`
 	Tag                    string                  `json:"tag"`
@@ -435,5 +450,13 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
 		config.StaticHosts = append(config.StaticHosts, mappings...)
 		config.StaticHosts = append(config.StaticHosts, mappings...)
 	}
 	}
 
 
+	if c.FakeDNS != nil {
+		fakeDNS, err := c.FakeDNS.Build()
+		if err != nil {
+			return nil, newError("failed to build fakedns").Base(err)
+		}
+		config.FakeDns = fakeDNS
+	}
+
 	return config, nil
 	return config, nil
 }
 }

+ 137 - 0
infra/conf/synthetic/dns/dns_test.go

@@ -11,6 +11,7 @@ import (
 	"google.golang.org/protobuf/runtime/protoiface"
 	"google.golang.org/protobuf/runtime/protoiface"
 
 
 	"github.com/v2fly/v2ray-core/v5/app/dns"
 	"github.com/v2fly/v2ray-core/v5/app/dns"
+	"github.com/v2fly/v2ray-core/v5/app/dns/fakedns"
 	"github.com/v2fly/v2ray-core/v5/common"
 	"github.com/v2fly/v2ray-core/v5/common"
 	"github.com/v2fly/v2ray-core/v5/common/net"
 	"github.com/v2fly/v2ray-core/v5/common/net"
 	"github.com/v2fly/v2ray-core/v5/common/platform/filesystem"
 	"github.com/v2fly/v2ray-core/v5/common/platform/filesystem"
@@ -149,5 +150,141 @@ func TestDNSConfigParsing(t *testing.T) {
 				DisableFallback: true,
 				DisableFallback: true,
 			},
 			},
 		},
 		},
+		{
+			Input: `{
+				"servers": [{
+					"address": "fakedns",
+					"tag": "fake",
+					"queryStrategy": "UseIPv6",
+					"fallbackStrategy": "disabledIfAnyMatch",
+					"fakedns": true
+				}, {
+					"address": "8.8.8.8",
+					"port": 5353,
+					"tag": "local",
+					"clientIp": "10.0.0.1",
+					"queryStrategy": "UseIP",
+					"cacheStrategy": "enabled",
+					"fallbackStrategy": "disabled",
+					"domains": ["domain:v2fly.org"],
+					"fakedns": ["198.19.0.0/16", "fc01::/18"]
+				}],
+				"hosts": {
+					"v2fly.org": "127.0.0.1",
+					"www.v2fly.org": ["1.2.3.4", "5.6.7.8"],
+					"domain:example.com": "google.com",
+					"geosite:test": ["127.0.0.1", "127.0.0.2"],
+					"keyword:google": ["8.8.8.8", "8.8.4.4"],
+					"regexp:.*\\.com": "8.8.4.4"
+				},
+				"fakedns": [
+					{ "ipPool": "198.18.0.0/16", "poolSize": 32768 },
+					{ "ipPool": "fc00::/18", "poolSize": 32768 }
+				],
+				"tag": "global",
+				"clientIp": "10.0.0.1",
+				"queryStrategy": "UseIPv4",
+				"cacheStrategy": "disabled",
+				"fallbackStrategy": "enabled"
+			}`,
+			Parser: parserCreator(),
+			Output: &dns.Config{
+				NameServer: []*dns.NameServer{
+					{
+						Address: &net.Endpoint{
+							Address: &net.IPOrDomain{
+								Address: &net.IPOrDomain_Domain{
+									Domain: "fakedns",
+								},
+							},
+							Network: net.Network_UDP,
+						},
+						Tag:              "fake",
+						QueryStrategy:    dns.QueryStrategy_USE_IP6.Enum(),
+						FallbackStrategy: dns.FallbackStrategy_DisabledIfAnyMatch.Enum(),
+						FakeDns: &fakedns.FakeDnsPoolMulti{
+							Pools: []*fakedns.FakeDnsPool{},
+						},
+					},
+					{
+						Address: &net.Endpoint{
+							Address: &net.IPOrDomain{
+								Address: &net.IPOrDomain_Ip{
+									Ip: []byte{8, 8, 8, 8},
+								},
+							},
+							Network: net.Network_UDP,
+							Port:    5353,
+						},
+						Tag:              "local",
+						ClientIp:         []byte{10, 0, 0, 1},
+						QueryStrategy:    dns.QueryStrategy_USE_IP.Enum(),
+						CacheStrategy:    dns.CacheStrategy_CacheEnabled.Enum(),
+						FallbackStrategy: dns.FallbackStrategy_Disabled.Enum(),
+						PrioritizedDomain: []*dns.NameServer_PriorityDomain{
+							{
+								Type:   dns.DomainMatchingType_Subdomain,
+								Domain: "v2fly.org",
+							},
+						},
+						OriginalRules: []*dns.NameServer_OriginalRule{
+							{
+								Rule: "domain:v2fly.org",
+								Size: 1,
+							},
+						},
+						FakeDns: &fakedns.FakeDnsPoolMulti{
+							Pools: []*fakedns.FakeDnsPool{
+								{IpPool: "198.19.0.0/16", LruSize: 65535},
+								{IpPool: "fc01::/18", LruSize: 65535},
+							},
+						},
+					},
+				},
+				StaticHosts: []*dns.HostMapping{
+					{
+						Type:          dns.DomainMatchingType_Subdomain,
+						Domain:        "example.com",
+						ProxiedDomain: "google.com",
+					},
+					{
+						Type:   dns.DomainMatchingType_Full,
+						Domain: "test.example.com",
+						Ip:     [][]byte{{127, 0, 0, 1}, {127, 0, 0, 2}},
+					},
+					{
+						Type:   dns.DomainMatchingType_Keyword,
+						Domain: "google",
+						Ip:     [][]byte{{8, 8, 8, 8}, {8, 8, 4, 4}},
+					},
+					{
+						Type:   dns.DomainMatchingType_Regex,
+						Domain: ".*\\.com",
+						Ip:     [][]byte{{8, 8, 4, 4}},
+					},
+					{
+						Type:   dns.DomainMatchingType_Full,
+						Domain: "v2fly.org",
+						Ip:     [][]byte{{127, 0, 0, 1}},
+					},
+					{
+						Type:   dns.DomainMatchingType_Full,
+						Domain: "www.v2fly.org",
+						Ip:     [][]byte{{1, 2, 3, 4}, {5, 6, 7, 8}},
+					},
+				},
+				FakeDns: &fakedns.FakeDnsPoolMulti{
+					Pools: []*fakedns.FakeDnsPool{
+						{IpPool: "198.18.0.0/16", LruSize: 32768},
+						{IpPool: "fc00::/18", LruSize: 32768},
+					},
+				},
+				Tag:              "global",
+				ClientIp:         []byte{10, 0, 0, 1},
+				QueryStrategy:    dns.QueryStrategy_USE_IP4,
+				CacheStrategy:    dns.CacheStrategy_CacheDisabled,
+				FallbackStrategy: dns.FallbackStrategy_Enabled,
+			},
+		},
 	})
 	})
 }
 }

+ 87 - 0
infra/conf/synthetic/dns/fakedns.go

@@ -0,0 +1,87 @@
+package dns
+
+import (
+	"encoding/json"
+	"net"
+
+	"github.com/v2fly/v2ray-core/v5/app/dns/fakedns"
+)
+
+type FakeDNSPoolElementConfig struct {
+	IPPool  string `json:"ipPool"`
+	LRUSize int64  `json:"poolSize"`
+}
+
+type FakeDNSConfig struct {
+	pool  *FakeDNSPoolElementConfig
+	pools []*FakeDNSPoolElementConfig
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
+func (f *FakeDNSConfig) UnmarshalJSON(data []byte) error {
+	var pool FakeDNSPoolElementConfig
+	var pools []*FakeDNSPoolElementConfig
+	var ipPools []string
+	switch {
+	case json.Unmarshal(data, &pool) == nil:
+		f.pool = &pool
+	case json.Unmarshal(data, &pools) == nil:
+		f.pools = pools
+	case json.Unmarshal(data, &ipPools) == nil:
+		f.pools = make([]*FakeDNSPoolElementConfig, 0, len(ipPools))
+		for _, ipPool := range ipPools {
+			_, ipNet, err := net.ParseCIDR(ipPool)
+			if err != nil {
+				return err
+			}
+			ones, bits := ipNet.Mask.Size()
+			sizeInBits := bits - ones
+			if sizeInBits > 16 { // At most 65536 ips for a IP pool
+				sizeInBits = 16
+			}
+			f.pools = append(f.pools, &FakeDNSPoolElementConfig{
+				IPPool:  ipPool,
+				LRUSize: (1 << sizeInBits) - 1,
+			})
+		}
+	default:
+		return newError("invalid fakedns config")
+	}
+	return nil
+}
+
+func (f *FakeDNSConfig) Build() (*fakedns.FakeDnsPoolMulti, error) {
+	fakeDNSPool := fakedns.FakeDnsPoolMulti{}
+
+	if f.pool != nil {
+		fakeDNSPool.Pools = append(fakeDNSPool.Pools, &fakedns.FakeDnsPool{
+			IpPool:  f.pool.IPPool,
+			LruSize: f.pool.LRUSize,
+		})
+		return &fakeDNSPool, nil
+	}
+
+	if f.pools != nil {
+		for _, v := range f.pools {
+			fakeDNSPool.Pools = append(fakeDNSPool.Pools, &fakedns.FakeDnsPool{IpPool: v.IPPool, LruSize: v.LRUSize})
+		}
+		return &fakeDNSPool, nil
+	}
+
+	return nil, newError("no valid FakeDNS config")
+}
+
+type FakeDNSConfigExtend struct { // Adds boolean value parsing for "fakedns" config
+	*FakeDNSConfig
+}
+
+func (f *FakeDNSConfigExtend) UnmarshalJSON(data []byte) error {
+	var enabled bool
+	if json.Unmarshal(data, &enabled) == nil {
+		if enabled {
+			f.FakeDNSConfig = &FakeDNSConfig{pools: []*FakeDNSPoolElementConfig{}}
+		}
+		return nil
+	}
+	return json.Unmarshal(data, &f.FakeDNSConfig)
+}

+ 0 - 129
infra/conf/v4/fakedns.go

@@ -1,129 +0,0 @@
-package v4
-
-import (
-	"encoding/json"
-	"strings"
-
-	"github.com/v2fly/v2ray-core/v5/app/dns/fakedns"
-)
-
-type FakeDNSPoolElementConfig struct {
-	IPPool  string `json:"ipPool"`
-	LRUSize int64  `json:"poolSize"`
-}
-
-type FakeDNSConfig struct {
-	pool  *FakeDNSPoolElementConfig
-	pools []*FakeDNSPoolElementConfig
-}
-
-// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
-func (f *FakeDNSConfig) UnmarshalJSON(data []byte) error {
-	var pool FakeDNSPoolElementConfig
-	var pools []*FakeDNSPoolElementConfig
-	switch {
-	case json.Unmarshal(data, &pool) == nil:
-		f.pool = &pool
-	case json.Unmarshal(data, &pools) == nil:
-		f.pools = pools
-	default:
-		return newError("invalid fakedns config")
-	}
-	return nil
-}
-
-func (f *FakeDNSConfig) Build() (*fakedns.FakeDnsPoolMulti, error) {
-	fakeDNSPool := fakedns.FakeDnsPoolMulti{}
-
-	if f.pool != nil {
-		fakeDNSPool.Pools = append(fakeDNSPool.Pools, &fakedns.FakeDnsPool{
-			IpPool:  f.pool.IPPool,
-			LruSize: f.pool.LRUSize,
-		})
-		return &fakeDNSPool, nil
-	}
-
-	if f.pools != nil {
-		for _, v := range f.pools {
-			fakeDNSPool.Pools = append(fakeDNSPool.Pools, &fakedns.FakeDnsPool{IpPool: v.IPPool, LruSize: v.LRUSize})
-		}
-		return &fakeDNSPool, nil
-	}
-
-	return nil, newError("no valid FakeDNS config")
-}
-
-type FakeDNSPostProcessingStage struct{}
-
-func (FakeDNSPostProcessingStage) Process(config *Config) error {
-	fakeDNSInUse := false
-	isIPv4Enable, isIPv6Enable := true, true
-
-	if config.DNSConfig != nil {
-		for _, v := range config.DNSConfig.Servers {
-			if v.Address.Family().IsDomain() && strings.EqualFold(v.Address.Domain(), "fakedns") {
-				fakeDNSInUse = true
-			}
-		}
-
-		switch strings.ToLower(config.DNSConfig.QueryStrategy) {
-		case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4":
-			isIPv4Enable, isIPv6Enable = true, false
-		case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6":
-			isIPv4Enable, isIPv6Enable = false, true
-		}
-	}
-
-	if fakeDNSInUse {
-		// Add a Fake DNS Config if there is none
-		if config.FakeDNS == nil {
-			config.FakeDNS = &FakeDNSConfig{}
-			switch {
-			case isIPv4Enable && isIPv6Enable:
-				config.FakeDNS.pools = []*FakeDNSPoolElementConfig{
-					{
-						IPPool:  "198.18.0.0/15",
-						LRUSize: 32768,
-					},
-					{
-						IPPool:  "fc00::/18",
-						LRUSize: 32768,
-					},
-				}
-			case !isIPv4Enable && isIPv6Enable:
-				config.FakeDNS.pool = &FakeDNSPoolElementConfig{
-					IPPool:  "fc00::/18",
-					LRUSize: 65535,
-				}
-			case isIPv4Enable && !isIPv6Enable:
-				config.FakeDNS.pool = &FakeDNSPoolElementConfig{
-					IPPool:  "198.18.0.0/15",
-					LRUSize: 65535,
-				}
-			}
-		}
-
-		found := false
-		// Check if there is a Outbound with necessary sniffer on
-		var inbounds []InboundDetourConfig
-
-		if len(config.InboundConfigs) > 0 {
-			inbounds = append(inbounds, config.InboundConfigs...)
-		}
-		for _, v := range inbounds {
-			if v.SniffingConfig != nil && v.SniffingConfig.Enabled && v.SniffingConfig.DestOverride != nil {
-				for _, dov := range *v.SniffingConfig.DestOverride {
-					if strings.EqualFold(dov, "fakedns") || strings.EqualFold(dov, "fakedns+others") {
-						found = true
-						break
-					}
-				}
-			}
-		}
-		if !found {
-			newError("Defined FakeDNS but haven't enabled FakeDNS destOverride at any inbound.").AtWarning().WriteToLog()
-		}
-	}
-
-	return nil
-}

+ 0 - 5
infra/conf/v4/init.go

@@ -1,5 +0,0 @@
-package v4
-
-func init() {
-	RegisterConfigureFilePostProcessingStage("FakeDNS", &FakeDNSPostProcessingStage{})
-}

+ 13 - 9
infra/conf/v4/v2ray.go

@@ -11,6 +11,7 @@ import (
 	"github.com/v2fly/v2ray-core/v5/app/proxyman"
 	"github.com/v2fly/v2ray-core/v5/app/proxyman"
 	"github.com/v2fly/v2ray-core/v5/app/stats"
 	"github.com/v2fly/v2ray-core/v5/app/stats"
 	"github.com/v2fly/v2ray-core/v5/common/serial"
 	"github.com/v2fly/v2ray-core/v5/common/serial"
+	"github.com/v2fly/v2ray-core/v5/features"
 	"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon"
 	"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon"
 	"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/loader"
 	"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/loader"
 	"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/muxcfg"
 	"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/muxcfg"
@@ -302,7 +303,7 @@ type Config struct {
 	API              *APIConfig              `json:"api"`
 	API              *APIConfig              `json:"api"`
 	Stats            *StatsConfig            `json:"stats"`
 	Stats            *StatsConfig            `json:"stats"`
 	Reverse          *ReverseConfig          `json:"reverse"`
 	Reverse          *ReverseConfig          `json:"reverse"`
-	FakeDNS          *FakeDNSConfig          `json:"fakeDns"`
+	FakeDNS          *dns.FakeDNSConfig      `json:"fakeDns"`
 	BrowserForwarder *BrowserForwarderConfig `json:"browserForwarder"`
 	BrowserForwarder *BrowserForwarderConfig `json:"browserForwarder"`
 	Observatory      *ObservatoryConfig      `json:"observatory"`
 	Observatory      *ObservatoryConfig      `json:"observatory"`
 	BurstObservatory *BurstObservatoryConfig `json:"burstObservatory"`
 	BurstObservatory *BurstObservatoryConfig `json:"burstObservatory"`
@@ -399,6 +400,17 @@ func (c *Config) Build() (*core.Config, error) {
 		config.App = append(config.App, serial.ToTypedMessage(routerConfig))
 		config.App = append(config.App, serial.ToTypedMessage(routerConfig))
 	}
 	}
 
 
+	if c.FakeDNS != nil {
+		features.PrintDeprecatedFeatureWarning("root fakedns settings")
+		if c.DNSConfig != nil {
+			c.DNSConfig.FakeDNS = c.FakeDNS
+		} else {
+			c.DNSConfig = &dns.DNSConfig{
+				FakeDNS: c.FakeDNS,
+			}
+		}
+	}
+
 	if c.DNSConfig != nil {
 	if c.DNSConfig != nil {
 		dnsApp, err := c.DNSConfig.Build()
 		dnsApp, err := c.DNSConfig.Build()
 		if err != nil {
 		if err != nil {
@@ -423,14 +435,6 @@ func (c *Config) Build() (*core.Config, error) {
 		config.App = append(config.App, serial.ToTypedMessage(r))
 		config.App = append(config.App, serial.ToTypedMessage(r))
 	}
 	}
 
 
-	if c.FakeDNS != nil {
-		r, err := c.FakeDNS.Build()
-		if err != nil {
-			return nil, err
-		}
-		config.App = append(config.App, serial.ToTypedMessage(r))
-	}
-
 	if c.BrowserForwarder != nil {
 	if c.BrowserForwarder != nil {
 		r, err := c.BrowserForwarder.Build()
 		r, err := c.BrowserForwarder.Build()
 		if err != nil {
 		if err != nil {

+ 4 - 7
proxy/dns/dns.go

@@ -56,6 +56,10 @@ type Handler struct {
 }
 }
 
 
 func (h *Handler) Init(config *Config, dnsClient dns.Client, policyManager policy.Manager) error {
 func (h *Handler) Init(config *Config, dnsClient dns.Client, policyManager policy.Manager) error {
+	// Enable FakeDNS for DNS outbound
+	if clientWithFakeDNS, ok := dnsClient.(dns.ClientWithFakeDNS); ok {
+		dnsClient = clientWithFakeDNS.AsFakeDNSClient()
+	}
 	h.client = dnsClient
 	h.client = dnsClient
 	h.timeout = policyManager.ForLevel(config.UserLevel).Timeouts.ConnectionIdle
 	h.timeout = policyManager.ForLevel(config.UserLevel).Timeouts.ConnectionIdle
 
 
@@ -236,13 +240,6 @@ func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string,
 
 
 	var ttl uint32 = 600
 	var ttl uint32 = 600
 
 
-	// Do NOT skip FakeDNS
-	if c, ok := h.client.(dns.ClientWithIPOption); ok {
-		c.SetFakeDNSOption(true)
-	} else {
-		newError("dns.Client doesn't implement ClientWithIPOption")
-	}
-
 	switch qType {
 	switch qType {
 	case dnsmessage.TypeA:
 	case dnsmessage.TypeA:
 		ips, err = h.ipv4Lookup.LookupIPv4(domain)
 		ips, err = h.ipv4Lookup.LookupIPv4(domain)

+ 5 - 18
proxy/freedom/freedom.go

@@ -65,24 +65,11 @@ func (h *Handler) policy() policy.Session {
 }
 }
 
 
 func (h *Handler) resolveIP(ctx context.Context, domain string, localAddr net.Address) net.Address {
 func (h *Handler) resolveIP(ctx context.Context, domain string, localAddr net.Address) net.Address {
-	if c, ok := h.dns.(dns.ClientWithIPOption); ok {
-		c.SetFakeDNSOption(false) // Skip FakeDNS
-	} else {
-		newError("DNS client doesn't implement ClientWithIPOption")
-	}
-
-	lookupFunc := h.dns.LookupIP
-	if h.config.DomainStrategy == Config_USE_IP4 || (localAddr != nil && localAddr.Family().IsIPv4()) {
-		if lookupIPv4, ok := h.dns.(dns.IPv4Lookup); ok {
-			lookupFunc = lookupIPv4.LookupIPv4
-		}
-	} else if h.config.DomainStrategy == Config_USE_IP6 || (localAddr != nil && localAddr.Family().IsIPv6()) {
-		if lookupIPv6, ok := h.dns.(dns.IPv6Lookup); ok {
-			lookupFunc = lookupIPv6.LookupIPv6
-		}
-	}
-
-	ips, err := lookupFunc(domain)
+	ips, err := dns.LookupIPWithOption(h.dns, domain, dns.IPOption{
+		IPv4Enable: h.config.DomainStrategy == Config_USE_IP || h.config.DomainStrategy == Config_USE_IP4 || (localAddr != nil && localAddr.Family().IsIPv4()),
+		IPv6Enable: h.config.DomainStrategy == Config_USE_IP || h.config.DomainStrategy == Config_USE_IP6 || (localAddr != nil && localAddr.Family().IsIPv6()),
+		FakeEnable: false,
+	})
 	if err != nil {
 	if err != nil {
 		newError("failed to get IP address for domain ", domain).Base(err).WriteToLog(session.ExportIDToError(ctx))
 		newError("failed to get IP address for domain ", domain).Base(err).WriteToLog(session.ExportIDToError(ctx))
 	}
 	}

+ 1 - 11
proxy/socks/client.go

@@ -104,17 +104,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
 	switch c.version {
 	switch c.version {
 	case Version_SOCKS4:
 	case Version_SOCKS4:
 		if request.Address.Family().IsDomain() {
 		if request.Address.Family().IsDomain() {
-			if d, ok := c.dns.(dns.ClientWithIPOption); ok {
-				d.SetFakeDNSOption(false) // Skip FakeDNS
-			} else {
-				newError("DNS client doesn't implement ClientWithIPOption")
-			}
-
-			lookupFunc := c.dns.LookupIP
-			if lookupIPv4, ok := c.dns.(dns.IPv4Lookup); ok {
-				lookupFunc = lookupIPv4.LookupIPv4
-			}
-			ips, err := lookupFunc(request.Address.Domain())
+			ips, err := dns.LookupIPWithOption(c.dns, request.Address.Domain(), dns.IPOption{IPv4Enable: true, IPv6Enable: false, FakeEnable: false})
 			if err != nil {
 			if err != nil {
 				return err
 				return err
 			} else if len(ips) == 0 {
 			} else if len(ips) == 0 {