Browse Source

Feat: [app/dns] Support per-client configuration (#1977)

* DNS: Support per-client configuration

* Add deprecated feature warnings for `skipFallback`, `disableCache`, `disableFallback`, `disableFallbackIfMatch`
Vigilans 3 years ago
parent
commit
d3b50bb989
7 changed files with 945 additions and 492 deletions
  1. 22 0
      app/dns/config.go
  2. 543 230
      app/dns/config.pb.go
  3. 53 9
      app/dns/config.proto
  4. 154 138
      app/dns/dns.go
  5. 79 103
      app/dns/nameserver.go
  6. 12 0
      features/dns/client.go
  7. 82 12
      infra/conf/synthetic/dns/dns.go

+ 22 - 0
app/dns/config.go

@@ -4,9 +4,12 @@
 package dns
 
 import (
+	"golang.org/x/net/dns/dnsmessage"
+
 	"github.com/v2fly/v2ray-core/v5/common/net"
 	"github.com/v2fly/v2ray-core/v5/common/strmatcher"
 	"github.com/v2fly/v2ray-core/v5/common/uuid"
+	"github.com/v2fly/v2ray-core/v5/features/dns"
 )
 
 var typeMap = map[DomainMatchingType]strmatcher.Type{
@@ -60,6 +63,25 @@ func toNetIP(addrs []net.Address) ([]net.IP, error) {
 	return ips, nil
 }
 
+func toIPOption(s QueryStrategy) dns.IPOption {
+	return dns.IPOption{
+		IPv4Enable: s == QueryStrategy_USE_IP || s == QueryStrategy_USE_IP4,
+		IPv6Enable: s == QueryStrategy_USE_IP || s == QueryStrategy_USE_IP6,
+		FakeEnable: false,
+	}
+}
+
+func toReqTypes(option dns.IPOption) []dnsmessage.Type {
+	var reqTypes []dnsmessage.Type
+	if option.IPv4Enable {
+		reqTypes = append(reqTypes, dnsmessage.TypeA)
+	}
+	if option.IPv6Enable {
+		reqTypes = append(reqTypes, dnsmessage.TypeAAAA)
+	}
+	return reqTypes
+}
+
 func generateRandomTag() string {
 	id := uuid.New()
 	return "v2ray.system." + id.String()

+ 543 - 230
app/dns/config.pb.go

@@ -118,6 +118,101 @@ func (QueryStrategy) EnumDescriptor() ([]byte, []int) {
 	return file_app_dns_config_proto_rawDescGZIP(), []int{1}
 }
 
+type CacheStrategy int32
+
+const (
+	CacheStrategy_CacheEnabled  CacheStrategy = 0
+	CacheStrategy_CacheDisabled CacheStrategy = 1
+)
+
+// Enum value maps for CacheStrategy.
+var (
+	CacheStrategy_name = map[int32]string{
+		0: "CacheEnabled",
+		1: "CacheDisabled",
+	}
+	CacheStrategy_value = map[string]int32{
+		"CacheEnabled":  0,
+		"CacheDisabled": 1,
+	}
+)
+
+func (x CacheStrategy) Enum() *CacheStrategy {
+	p := new(CacheStrategy)
+	*p = x
+	return p
+}
+
+func (x CacheStrategy) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CacheStrategy) Descriptor() protoreflect.EnumDescriptor {
+	return file_app_dns_config_proto_enumTypes[2].Descriptor()
+}
+
+func (CacheStrategy) Type() protoreflect.EnumType {
+	return &file_app_dns_config_proto_enumTypes[2]
+}
+
+func (x CacheStrategy) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use CacheStrategy.Descriptor instead.
+func (CacheStrategy) EnumDescriptor() ([]byte, []int) {
+	return file_app_dns_config_proto_rawDescGZIP(), []int{2}
+}
+
+type FallbackStrategy int32
+
+const (
+	FallbackStrategy_Enabled            FallbackStrategy = 0
+	FallbackStrategy_Disabled           FallbackStrategy = 1
+	FallbackStrategy_DisabledIfAnyMatch FallbackStrategy = 2
+)
+
+// Enum value maps for FallbackStrategy.
+var (
+	FallbackStrategy_name = map[int32]string{
+		0: "Enabled",
+		1: "Disabled",
+		2: "DisabledIfAnyMatch",
+	}
+	FallbackStrategy_value = map[string]int32{
+		"Enabled":            0,
+		"Disabled":           1,
+		"DisabledIfAnyMatch": 2,
+	}
+)
+
+func (x FallbackStrategy) Enum() *FallbackStrategy {
+	p := new(FallbackStrategy)
+	*p = x
+	return p
+}
+
+func (x FallbackStrategy) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (FallbackStrategy) Descriptor() protoreflect.EnumDescriptor {
+	return file_app_dns_config_proto_enumTypes[3].Descriptor()
+}
+
+func (FallbackStrategy) Type() protoreflect.EnumType {
+	return &file_app_dns_config_proto_enumTypes[3]
+}
+
+func (x FallbackStrategy) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use FallbackStrategy.Descriptor instead.
+func (FallbackStrategy) EnumDescriptor() ([]byte, []int) {
+	return file_app_dns_config_proto_rawDescGZIP(), []int{3}
+}
+
 type NameServer struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -125,10 +220,17 @@ type NameServer struct {
 
 	Address           *net.Endpoint                `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
 	ClientIp          []byte                       `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
-	SkipFallback      bool                         `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
+	Tag               string                       `protobuf:"bytes,7,opt,name=tag,proto3" json:"tag,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"`
 	OriginalRules     []*NameServer_OriginalRule   `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
+	// Deprecated. Use fallback_strategy.
+	//
+	// Deprecated: Do not use.
+	SkipFallback     bool              `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
+	QueryStrategy    *QueryStrategy    `protobuf:"varint,8,opt,name=query_strategy,json=queryStrategy,proto3,enum=v2ray.core.app.dns.QueryStrategy,oneof" json:"query_strategy,omitempty"`
+	CacheStrategy    *CacheStrategy    `protobuf:"varint,9,opt,name=cache_strategy,json=cacheStrategy,proto3,enum=v2ray.core.app.dns.CacheStrategy,oneof" json:"cache_strategy,omitempty"`
+	FallbackStrategy *FallbackStrategy `protobuf:"varint,10,opt,name=fallback_strategy,json=fallbackStrategy,proto3,enum=v2ray.core.app.dns.FallbackStrategy,oneof" json:"fallback_strategy,omitempty"`
 }
 
 func (x *NameServer) Reset() {
@@ -177,11 +279,11 @@ func (x *NameServer) GetClientIp() []byte {
 	return nil
 }
 
-func (x *NameServer) GetSkipFallback() bool {
+func (x *NameServer) GetTag() string {
 	if x != nil {
-		return x.SkipFallback
+		return x.Tag
 	}
-	return false
+	return ""
 }
 
 func (x *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain {
@@ -205,6 +307,35 @@ func (x *NameServer) GetOriginalRules() []*NameServer_OriginalRule {
 	return nil
 }
 
+// Deprecated: Do not use.
+func (x *NameServer) GetSkipFallback() bool {
+	if x != nil {
+		return x.SkipFallback
+	}
+	return false
+}
+
+func (x *NameServer) GetQueryStrategy() QueryStrategy {
+	if x != nil && x.QueryStrategy != nil {
+		return *x.QueryStrategy
+	}
+	return QueryStrategy_USE_IP
+}
+
+func (x *NameServer) GetCacheStrategy() CacheStrategy {
+	if x != nil && x.CacheStrategy != nil {
+		return *x.CacheStrategy
+	}
+	return CacheStrategy_CacheEnabled
+}
+
+func (x *NameServer) GetFallbackStrategy() FallbackStrategy {
+	if x != nil && x.FallbackStrategy != nil {
+		return *x.FallbackStrategy
+	}
+	return FallbackStrategy_Enabled
+}
+
 type HostMapping struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -303,10 +434,24 @@ type Config struct {
 	// Tag is the inbound tag of DNS client.
 	Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
 	// DisableCache disables DNS cache
-	DisableCache           bool          `protobuf:"varint,8,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
-	QueryStrategy          QueryStrategy `protobuf:"varint,9,opt,name=query_strategy,json=queryStrategy,proto3,enum=v2ray.core.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
-	DisableFallback        bool          `protobuf:"varint,10,opt,name=disableFallback,proto3" json:"disableFallback,omitempty"`
-	DisableFallbackIfMatch bool          `protobuf:"varint,11,opt,name=disableFallbackIfMatch,proto3" json:"disableFallbackIfMatch,omitempty"`
+	// Deprecated. Use cache_strategy.
+	//
+	// Deprecated: Do not use.
+	DisableCache bool `protobuf:"varint,8,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
+	// Deprecated. Use fallback_strategy.
+	//
+	// Deprecated: Do not use.
+	DisableFallback bool `protobuf:"varint,10,opt,name=disableFallback,proto3" json:"disableFallback,omitempty"`
+	// Deprecated. Use fallback_strategy.
+	//
+	// Deprecated: Do not use.
+	DisableFallbackIfMatch bool `protobuf:"varint,11,opt,name=disableFallbackIfMatch,proto3" json:"disableFallbackIfMatch,omitempty"`
+	// Default query strategy (IPv4, IPv6, or both) for each name server.
+	QueryStrategy QueryStrategy `protobuf:"varint,9,opt,name=query_strategy,json=queryStrategy,proto3,enum=v2ray.core.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
+	// Default cache strategy for each name server.
+	CacheStrategy CacheStrategy `protobuf:"varint,12,opt,name=cache_strategy,json=cacheStrategy,proto3,enum=v2ray.core.app.dns.CacheStrategy" json:"cache_strategy,omitempty"`
+	// Default fallback strategy for each name server.
+	FallbackStrategy FallbackStrategy `protobuf:"varint,13,opt,name=fallback_strategy,json=fallbackStrategy,proto3,enum=v2ray.core.app.dns.FallbackStrategy" json:"fallback_strategy,omitempty"`
 }
 
 func (x *Config) Reset() {
@@ -385,6 +530,7 @@ func (x *Config) GetTag() string {
 	return ""
 }
 
+// Deprecated: Do not use.
 func (x *Config) GetDisableCache() bool {
 	if x != nil {
 		return x.DisableCache
@@ -392,6 +538,22 @@ func (x *Config) GetDisableCache() bool {
 	return false
 }
 
+// Deprecated: Do not use.
+func (x *Config) GetDisableFallback() bool {
+	if x != nil {
+		return x.DisableFallback
+	}
+	return false
+}
+
+// Deprecated: Do not use.
+func (x *Config) GetDisableFallbackIfMatch() bool {
+	if x != nil {
+		return x.DisableFallbackIfMatch
+	}
+	return false
+}
+
 func (x *Config) GetQueryStrategy() QueryStrategy {
 	if x != nil {
 		return x.QueryStrategy
@@ -399,18 +561,18 @@ func (x *Config) GetQueryStrategy() QueryStrategy {
 	return QueryStrategy_USE_IP
 }
 
-func (x *Config) GetDisableFallback() bool {
+func (x *Config) GetCacheStrategy() CacheStrategy {
 	if x != nil {
-		return x.DisableFallback
+		return x.CacheStrategy
 	}
-	return false
+	return CacheStrategy_CacheEnabled
 }
 
-func (x *Config) GetDisableFallbackIfMatch() bool {
+func (x *Config) GetFallbackStrategy() FallbackStrategy {
 	if x != nil {
-		return x.DisableFallbackIfMatch
+		return x.FallbackStrategy
 	}
-	return false
+	return FallbackStrategy_Enabled
 }
 
 type SimplifiedConfig struct {
@@ -427,10 +589,24 @@ type SimplifiedConfig struct {
 	// Tag is the inbound tag of DNS client.
 	Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
 	// DisableCache disables DNS cache
-	DisableCache           bool          `protobuf:"varint,8,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
-	QueryStrategy          QueryStrategy `protobuf:"varint,9,opt,name=query_strategy,json=queryStrategy,proto3,enum=v2ray.core.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
-	DisableFallback        bool          `protobuf:"varint,10,opt,name=disableFallback,proto3" json:"disableFallback,omitempty"`
-	DisableFallbackIfMatch bool          `protobuf:"varint,11,opt,name=disableFallbackIfMatch,proto3" json:"disableFallbackIfMatch,omitempty"`
+	// Deprecated. Use cache_strategy.
+	//
+	// Deprecated: Do not use.
+	DisableCache bool `protobuf:"varint,8,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
+	// Deprecated. Use fallback_strategy.
+	//
+	// Deprecated: Do not use.
+	DisableFallback bool `protobuf:"varint,10,opt,name=disableFallback,proto3" json:"disableFallback,omitempty"`
+	// Deprecated. Use fallback_strategy.
+	//
+	// Deprecated: Do not use.
+	DisableFallbackIfMatch bool `protobuf:"varint,11,opt,name=disableFallbackIfMatch,proto3" json:"disableFallbackIfMatch,omitempty"`
+	// Default query strategy (IPv4, IPv6, or both) for each name server.
+	QueryStrategy QueryStrategy `protobuf:"varint,9,opt,name=query_strategy,json=queryStrategy,proto3,enum=v2ray.core.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
+	// Default cache strategy for each name server.
+	CacheStrategy CacheStrategy `protobuf:"varint,12,opt,name=cache_strategy,json=cacheStrategy,proto3,enum=v2ray.core.app.dns.CacheStrategy" json:"cache_strategy,omitempty"`
+	// Default fallback strategy for each name server.
+	FallbackStrategy FallbackStrategy `protobuf:"varint,13,opt,name=fallback_strategy,json=fallbackStrategy,proto3,enum=v2ray.core.app.dns.FallbackStrategy" json:"fallback_strategy,omitempty"`
 }
 
 func (x *SimplifiedConfig) Reset() {
@@ -493,6 +669,7 @@ func (x *SimplifiedConfig) GetTag() string {
 	return ""
 }
 
+// Deprecated: Do not use.
 func (x *SimplifiedConfig) GetDisableCache() bool {
 	if x != nil {
 		return x.DisableCache
@@ -500,6 +677,22 @@ func (x *SimplifiedConfig) GetDisableCache() bool {
 	return false
 }
 
+// Deprecated: Do not use.
+func (x *SimplifiedConfig) GetDisableFallback() bool {
+	if x != nil {
+		return x.DisableFallback
+	}
+	return false
+}
+
+// Deprecated: Do not use.
+func (x *SimplifiedConfig) GetDisableFallbackIfMatch() bool {
+	if x != nil {
+		return x.DisableFallbackIfMatch
+	}
+	return false
+}
+
 func (x *SimplifiedConfig) GetQueryStrategy() QueryStrategy {
 	if x != nil {
 		return x.QueryStrategy
@@ -507,18 +700,18 @@ func (x *SimplifiedConfig) GetQueryStrategy() QueryStrategy {
 	return QueryStrategy_USE_IP
 }
 
-func (x *SimplifiedConfig) GetDisableFallback() bool {
+func (x *SimplifiedConfig) GetCacheStrategy() CacheStrategy {
 	if x != nil {
-		return x.DisableFallback
+		return x.CacheStrategy
 	}
-	return false
+	return CacheStrategy_CacheEnabled
 }
 
-func (x *SimplifiedConfig) GetDisableFallbackIfMatch() bool {
+func (x *SimplifiedConfig) GetFallbackStrategy() FallbackStrategy {
 	if x != nil {
-		return x.DisableFallbackIfMatch
+		return x.FallbackStrategy
 	}
-	return false
+	return FallbackStrategy_Enabled
 }
 
 type SimplifiedHostMapping struct {
@@ -601,10 +794,17 @@ type SimplifiedNameServer struct {
 
 	Address           *net.Endpoint                          `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
 	ClientIp          string                                 `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
-	SkipFallback      bool                                   `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
+	Tag               string                                 `protobuf:"bytes,7,opt,name=tag,proto3" json:"tag,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"`
 	OriginalRules     []*SimplifiedNameServer_OriginalRule   `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
+	// Deprecated. Use fallback_strategy.
+	//
+	// Deprecated: Do not use.
+	SkipFallback     bool              `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
+	QueryStrategy    *QueryStrategy    `protobuf:"varint,8,opt,name=query_strategy,json=queryStrategy,proto3,enum=v2ray.core.app.dns.QueryStrategy,oneof" json:"query_strategy,omitempty"`
+	CacheStrategy    *CacheStrategy    `protobuf:"varint,9,opt,name=cache_strategy,json=cacheStrategy,proto3,enum=v2ray.core.app.dns.CacheStrategy,oneof" json:"cache_strategy,omitempty"`
+	FallbackStrategy *FallbackStrategy `protobuf:"varint,10,opt,name=fallback_strategy,json=fallbackStrategy,proto3,enum=v2ray.core.app.dns.FallbackStrategy,oneof" json:"fallback_strategy,omitempty"`
 }
 
 func (x *SimplifiedNameServer) Reset() {
@@ -653,11 +853,11 @@ func (x *SimplifiedNameServer) GetClientIp() string {
 	return ""
 }
 
-func (x *SimplifiedNameServer) GetSkipFallback() bool {
+func (x *SimplifiedNameServer) GetTag() string {
 	if x != nil {
-		return x.SkipFallback
+		return x.Tag
 	}
-	return false
+	return ""
 }
 
 func (x *SimplifiedNameServer) GetPrioritizedDomain() []*SimplifiedNameServer_PriorityDomain {
@@ -681,6 +881,35 @@ func (x *SimplifiedNameServer) GetOriginalRules() []*SimplifiedNameServer_Origin
 	return nil
 }
 
+// Deprecated: Do not use.
+func (x *SimplifiedNameServer) GetSkipFallback() bool {
+	if x != nil {
+		return x.SkipFallback
+	}
+	return false
+}
+
+func (x *SimplifiedNameServer) GetQueryStrategy() QueryStrategy {
+	if x != nil && x.QueryStrategy != nil {
+		return *x.QueryStrategy
+	}
+	return QueryStrategy_USE_IP
+}
+
+func (x *SimplifiedNameServer) GetCacheStrategy() CacheStrategy {
+	if x != nil && x.CacheStrategy != nil {
+		return *x.CacheStrategy
+	}
+	return CacheStrategy_CacheEnabled
+}
+
+func (x *SimplifiedNameServer) GetFallbackStrategy() FallbackStrategy {
+	if x != nil && x.FallbackStrategy != nil {
+		return *x.FallbackStrategy
+	}
+	return FallbackStrategy_Enabled
+}
+
 type NameServer_PriorityDomain struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -914,179 +1143,249 @@ var file_app_dns_config_proto_rawDesc = []byte{
 	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, 0x99, 0x04, 0x0a, 0x0a, 0x4e,
+	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, 0x22, 0x0a, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
-	0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c,
-	0x6c, 0x62, 0x61, 0x63, 0x6b, 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, 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, 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,
+	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, 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, 0xf7, 0x04, 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, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61,
-	0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c,
-	0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 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, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,
-	0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52,
-	0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
-	0x12, 0x36, 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,
-	0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
-	0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 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, 0xca, 0x03, 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, 0x22,
-	0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08,
-	0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63,
-	0x68, 0x65, 0x12, 0x48, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61,
+	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,
+	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, 0xa0, 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,
+	0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67,
+	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, 0x28, 0x0a, 0x0f,
-	0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18,
-	0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61,
-	0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x36, 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, 0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46,
-	0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 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, 0xb7, 0x04,
-	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, 0x22,
-	0x0a, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x06,
-	0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61,
-	0x63, 0x6b, 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, 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, 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, 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,
+	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, 0xf3, 0x04, 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,
+	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, 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, 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,
 }
 
 var (
@@ -1101,53 +1400,65 @@ func file_app_dns_config_proto_rawDescGZIP() []byte {
 	return file_app_dns_config_proto_rawDescData
 }
 
-var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
 var file_app_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
 var file_app_dns_config_proto_goTypes = []interface{}{
 	(DomainMatchingType)(0),                     // 0: v2ray.core.app.dns.DomainMatchingType
 	(QueryStrategy)(0),                          // 1: v2ray.core.app.dns.QueryStrategy
-	(*NameServer)(nil),                          // 2: v2ray.core.app.dns.NameServer
-	(*HostMapping)(nil),                         // 3: v2ray.core.app.dns.HostMapping
-	(*Config)(nil),                              // 4: v2ray.core.app.dns.Config
-	(*SimplifiedConfig)(nil),                    // 5: v2ray.core.app.dns.SimplifiedConfig
-	(*SimplifiedHostMapping)(nil),               // 6: v2ray.core.app.dns.SimplifiedHostMapping
-	(*SimplifiedNameServer)(nil),                // 7: v2ray.core.app.dns.SimplifiedNameServer
-	(*NameServer_PriorityDomain)(nil),           // 8: v2ray.core.app.dns.NameServer.PriorityDomain
-	(*NameServer_OriginalRule)(nil),             // 9: v2ray.core.app.dns.NameServer.OriginalRule
-	nil,                                         // 10: v2ray.core.app.dns.Config.HostsEntry
-	(*SimplifiedNameServer_PriorityDomain)(nil), // 11: v2ray.core.app.dns.SimplifiedNameServer.PriorityDomain
-	(*SimplifiedNameServer_OriginalRule)(nil),   // 12: v2ray.core.app.dns.SimplifiedNameServer.OriginalRule
-	(*net.Endpoint)(nil),                        // 13: v2ray.core.common.net.Endpoint
-	(*routercommon.GeoIP)(nil),                  // 14: v2ray.core.app.router.routercommon.GeoIP
-	(*net.IPOrDomain)(nil),                      // 15: v2ray.core.common.net.IPOrDomain
+	(CacheStrategy)(0),                          // 2: v2ray.core.app.dns.CacheStrategy
+	(FallbackStrategy)(0),                       // 3: v2ray.core.app.dns.FallbackStrategy
+	(*NameServer)(nil),                          // 4: v2ray.core.app.dns.NameServer
+	(*HostMapping)(nil),                         // 5: v2ray.core.app.dns.HostMapping
+	(*Config)(nil),                              // 6: v2ray.core.app.dns.Config
+	(*SimplifiedConfig)(nil),                    // 7: v2ray.core.app.dns.SimplifiedConfig
+	(*SimplifiedHostMapping)(nil),               // 8: v2ray.core.app.dns.SimplifiedHostMapping
+	(*SimplifiedNameServer)(nil),                // 9: v2ray.core.app.dns.SimplifiedNameServer
+	(*NameServer_PriorityDomain)(nil),           // 10: v2ray.core.app.dns.NameServer.PriorityDomain
+	(*NameServer_OriginalRule)(nil),             // 11: v2ray.core.app.dns.NameServer.OriginalRule
+	nil,                                         // 12: v2ray.core.app.dns.Config.HostsEntry
+	(*SimplifiedNameServer_PriorityDomain)(nil), // 13: v2ray.core.app.dns.SimplifiedNameServer.PriorityDomain
+	(*SimplifiedNameServer_OriginalRule)(nil),   // 14: v2ray.core.app.dns.SimplifiedNameServer.OriginalRule
+	(*net.Endpoint)(nil),                        // 15: v2ray.core.common.net.Endpoint
+	(*routercommon.GeoIP)(nil),                  // 16: v2ray.core.app.router.routercommon.GeoIP
+	(*net.IPOrDomain)(nil),                      // 17: v2ray.core.common.net.IPOrDomain
 }
 var file_app_dns_config_proto_depIdxs = []int32{
-	13, // 0: v2ray.core.app.dns.NameServer.address:type_name -> v2ray.core.common.net.Endpoint
-	8,  // 1: v2ray.core.app.dns.NameServer.prioritized_domain:type_name -> v2ray.core.app.dns.NameServer.PriorityDomain
-	14, // 2: v2ray.core.app.dns.NameServer.geoip:type_name -> v2ray.core.app.router.routercommon.GeoIP
-	9,  // 3: v2ray.core.app.dns.NameServer.original_rules:type_name -> v2ray.core.app.dns.NameServer.OriginalRule
-	0,  // 4: v2ray.core.app.dns.HostMapping.type:type_name -> v2ray.core.app.dns.DomainMatchingType
-	13, // 5: v2ray.core.app.dns.Config.NameServers:type_name -> v2ray.core.common.net.Endpoint
-	2,  // 6: v2ray.core.app.dns.Config.name_server:type_name -> v2ray.core.app.dns.NameServer
-	10, // 7: v2ray.core.app.dns.Config.Hosts:type_name -> v2ray.core.app.dns.Config.HostsEntry
-	3,  // 8: v2ray.core.app.dns.Config.static_hosts:type_name -> v2ray.core.app.dns.HostMapping
-	1,  // 9: v2ray.core.app.dns.Config.query_strategy:type_name -> v2ray.core.app.dns.QueryStrategy
-	7,  // 10: v2ray.core.app.dns.SimplifiedConfig.name_server:type_name -> v2ray.core.app.dns.SimplifiedNameServer
-	3,  // 11: v2ray.core.app.dns.SimplifiedConfig.static_hosts:type_name -> v2ray.core.app.dns.HostMapping
-	1,  // 12: v2ray.core.app.dns.SimplifiedConfig.query_strategy:type_name -> v2ray.core.app.dns.QueryStrategy
-	0,  // 13: v2ray.core.app.dns.SimplifiedHostMapping.type:type_name -> v2ray.core.app.dns.DomainMatchingType
-	13, // 14: v2ray.core.app.dns.SimplifiedNameServer.address:type_name -> v2ray.core.common.net.Endpoint
-	11, // 15: v2ray.core.app.dns.SimplifiedNameServer.prioritized_domain:type_name -> v2ray.core.app.dns.SimplifiedNameServer.PriorityDomain
-	14, // 16: v2ray.core.app.dns.SimplifiedNameServer.geoip:type_name -> v2ray.core.app.router.routercommon.GeoIP
-	12, // 17: v2ray.core.app.dns.SimplifiedNameServer.original_rules:type_name -> v2ray.core.app.dns.SimplifiedNameServer.OriginalRule
-	0,  // 18: v2ray.core.app.dns.NameServer.PriorityDomain.type:type_name -> v2ray.core.app.dns.DomainMatchingType
-	15, // 19: v2ray.core.app.dns.Config.HostsEntry.value:type_name -> v2ray.core.common.net.IPOrDomain
-	0,  // 20: v2ray.core.app.dns.SimplifiedNameServer.PriorityDomain.type:type_name -> v2ray.core.app.dns.DomainMatchingType
-	21, // [21:21] is the sub-list for method output_type
-	21, // [21:21] is the sub-list for method input_type
-	21, // [21:21] is the sub-list for extension type_name
-	21, // [21:21] is the sub-list for extension extendee
-	0,  // [0:21] is the sub-list for field type_name
+	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
+	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
+	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
 }
 
 func init() { file_app_dns_config_proto_init() }
@@ -1277,12 +1588,14 @@ func file_app_dns_config_proto_init() {
 			}
 		}
 	}
+	file_app_dns_config_proto_msgTypes[0].OneofWrappers = []interface{}{}
+	file_app_dns_config_proto_msgTypes[5].OneofWrappers = []interface{}{}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_app_dns_config_proto_rawDesc,
-			NumEnums:      2,
+			NumEnums:      4,
 			NumMessages:   11,
 			NumExtensions: 0,
 			NumServices:   0,

+ 53 - 9
app/dns/config.proto

@@ -15,7 +15,7 @@ import "common/protoext/extensions.proto";
 message NameServer {
   v2ray.core.common.net.Endpoint address = 1;
   bytes client_ip = 5;
-  bool skipFallback = 6;
+  string tag = 7;
 
   message PriorityDomain {
     DomainMatchingType type = 1;
@@ -30,6 +30,13 @@ message NameServer {
   repeated PriorityDomain prioritized_domain = 2;
   repeated v2ray.core.app.router.routercommon.GeoIP geoip = 3;
   repeated OriginalRule original_rules = 4;
+
+  // Deprecated. Use fallback_strategy.
+  bool skipFallback = 6 [deprecated = true];
+
+  optional QueryStrategy query_strategy = 8;
+  optional CacheStrategy cache_strategy = 9;
+  optional FallbackStrategy fallback_strategy = 10;
 }
 
 enum DomainMatchingType {
@@ -45,6 +52,16 @@ enum QueryStrategy {
   USE_IP6 = 2;
 }
 
+enum CacheStrategy {
+  CacheEnabled = 0;
+  CacheDisabled = 1;
+}
+
+enum FallbackStrategy {
+  Enabled = 0;
+  Disabled = 1;
+  DisabledIfAnyMatch = 2;
+}
 
 message HostMapping {
   DomainMatchingType type = 1;
@@ -82,13 +99,23 @@ message Config {
   reserved 7;
 
   // DisableCache disables DNS cache
-  bool disableCache = 8;
+  // Deprecated. Use cache_strategy.
+  bool disableCache = 8 [deprecated = true];
+
+  // Deprecated. Use fallback_strategy.
+  bool disableFallback = 10 [deprecated = true];
 
+  // Deprecated. Use fallback_strategy.
+  bool disableFallbackIfMatch = 11 [deprecated = true];
+
+  // Default query strategy (IPv4, IPv6, or both) for each name server.
   QueryStrategy query_strategy = 9;
 
-  bool disableFallback = 10;
+  // Default cache strategy for each name server.
+  CacheStrategy cache_strategy = 12;
 
-  bool disableFallbackIfMatch = 11;
+  // Default fallback strategy for each name server.
+  FallbackStrategy fallback_strategy = 13;
 }
 
 
@@ -121,13 +148,23 @@ message SimplifiedConfig {
   reserved 7;
 
   // DisableCache disables DNS cache
-  bool disableCache = 8;
+  // Deprecated. Use cache_strategy.
+  bool disableCache = 8 [deprecated = true];
+
+  // Deprecated. Use fallback_strategy.
+  bool disableFallback = 10 [deprecated = true];
+
+  // Deprecated. Use fallback_strategy.
+  bool disableFallbackIfMatch = 11 [deprecated = true];
 
+  // Default query strategy (IPv4, IPv6, or both) for each name server.
   QueryStrategy query_strategy = 9;
 
-  bool disableFallback = 10;
+  // Default cache strategy for each name server.
+  CacheStrategy cache_strategy = 12;
 
-  bool disableFallbackIfMatch = 11;
+  // Default fallback strategy for each name server.
+  FallbackStrategy fallback_strategy = 13;
 }
 
 
@@ -145,7 +182,7 @@ message SimplifiedHostMapping {
 message SimplifiedNameServer {
   v2ray.core.common.net.Endpoint address = 1;
   string client_ip = 5;
-  bool skipFallback = 6;
+  string tag = 7;
 
   message PriorityDomain {
     DomainMatchingType type = 1;
@@ -160,4 +197,11 @@ message SimplifiedNameServer {
   repeated PriorityDomain prioritized_domain = 2;
   repeated v2ray.core.app.router.routercommon.GeoIP geoip = 3;
   repeated OriginalRule original_rules = 4;
-}
+
+  // Deprecated. Use fallback_strategy.
+  bool skipFallback = 6 [deprecated = true];
+
+  optional QueryStrategy query_strategy = 8;
+  optional CacheStrategy cache_strategy = 9;
+  optional FallbackStrategy fallback_strategy = 10;
+}

+ 154 - 138
app/dns/dns.go

@@ -28,16 +28,13 @@ import (
 // DNS is a DNS rely server.
 type DNS struct {
 	sync.Mutex
-	tag                    string
-	disableCache           bool
-	disableFallback        bool
-	disableFallbackIfMatch bool
-	ipOption               *dns.IPOption
-	hosts                  *StaticHosts
-	clients                []*Client
-	ctx                    context.Context
-	domainMatcher          strmatcher.IndexMatcher
-	matcherInfos           []DomainMatcherInfo
+	ipOption      dns.IPOption
+	hosts         *StaticHosts
+	clients       []*Client
+	ctx           context.Context
+	clientTags    map[string]bool
+	domainMatcher strmatcher.IndexMatcher
+	matcherInfos  []DomainMatcherInfo
 }
 
 // DomainMatcherInfo contains information attached to index returned by Server.domainMatcher
@@ -48,88 +45,31 @@ type DomainMatcherInfo struct {
 
 // New creates a new DNS server with given configuration.
 func New(ctx context.Context, config *Config) (*DNS, error) {
-	var tag string
-	if len(config.Tag) > 0 {
-		tag = config.Tag
-	} else {
-		tag = generateRandomTag()
-	}
-
-	var clientIP net.IP
-	switch len(config.ClientIp) {
-	case 0, net.IPv4len, net.IPv6len:
-		clientIP = net.IP(config.ClientIp)
-	default:
-		return nil, newError("unexpected client IP length ", len(config.ClientIp))
-	}
-
-	var ipOption *dns.IPOption
-	switch config.QueryStrategy {
-	case QueryStrategy_USE_IP:
-		ipOption = &dns.IPOption{
-			IPv4Enable: true,
-			IPv6Enable: true,
-			FakeEnable: false,
-		}
-	case QueryStrategy_USE_IP4:
-		ipOption = &dns.IPOption{
-			IPv4Enable: true,
-			IPv6Enable: false,
-			FakeEnable: false,
-		}
-	case QueryStrategy_USE_IP6:
-		ipOption = &dns.IPOption{
-			IPv4Enable: false,
-			IPv6Enable: true,
-			FakeEnable: false,
-		}
-	}
-
+	// Create static hosts
 	hosts, err := NewStaticHosts(config.StaticHosts, config.Hosts)
 	if err != nil {
 		return nil, newError("failed to create hosts").Base(err)
 	}
 
+	// Create name servers from legacy configs
 	clients := []*Client{}
-	domainRuleCount := 0
-	for _, ns := range config.NameServer {
-		domainRuleCount += len(ns.PrioritizedDomain)
-	}
-
-	// MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1
-	matcherInfos := make([]DomainMatcherInfo, domainRuleCount+1)
-	domainMatcher := &strmatcher.LinearIndexMatcher{}
-	geoipContainer := router.GeoIPMatcherContainer{}
-
 	for _, endpoint := range config.NameServers {
 		features.PrintDeprecatedFeatureWarning("simple DNS server")
-		client, err := NewSimpleClient(ctx, endpoint, clientIP)
+		client, err := NewClient(ctx, &NameServer{Address: endpoint}, config)
 		if err != nil {
 			return nil, newError("failed to create client").Base(err)
 		}
 		clients = append(clients, client)
 	}
 
-	for _, ns := range config.NameServer {
-		clientIdx := len(clients)
-		updateDomain := func(domainRule strmatcher.Matcher, originalRuleIdx int, matcherInfos []DomainMatcherInfo) error {
-			midx := domainMatcher.Add(domainRule)
-			matcherInfos[midx] = DomainMatcherInfo{
-				clientIdx:     uint16(clientIdx),
-				domainRuleIdx: uint16(originalRuleIdx),
-			}
-			return nil
-		}
-
-		myClientIP := clientIP
-		switch len(ns.ClientIp) {
-		case net.IPv4len, net.IPv6len:
-			myClientIP = net.IP(ns.ClientIp)
-		}
-		client, err := NewClient(ctx, ns, myClientIP, geoipContainer, &matcherInfos, updateDomain)
+	// Create name servers
+	nsClientMap := map[int]int{}
+	for nsIdx, ns := range config.NameServer {
+		client, err := NewClient(ctx, ns, config)
 		if err != nil {
 			return nil, newError("failed to create client").Base(err)
 		}
+		nsClientMap[nsIdx] = len(clients)
 		clients = append(clients, client)
 	}
 
@@ -138,20 +78,94 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
 		clients = append(clients, NewLocalDNSClient())
 	}
 
+	// Establish members related to global DNS state
+	domainMatcher, matcherInfos, err := establishDomainRules(config, clients, nsClientMap)
+	if err != nil {
+		return nil, err
+	}
+	if err := establishExpectedIPs(config, clients, nsClientMap); err != nil {
+		return nil, err
+	}
+	clientTags := make(map[string]bool)
+	for _, client := range clients {
+		clientTags[client.tag] = true
+	}
+
 	return &DNS{
-		tag:                    tag,
-		hosts:                  hosts,
-		ipOption:               ipOption,
-		clients:                clients,
-		ctx:                    ctx,
-		domainMatcher:          domainMatcher,
-		matcherInfos:           matcherInfos,
-		disableCache:           config.DisableCache,
-		disableFallback:        config.DisableFallback,
-		disableFallbackIfMatch: config.DisableFallbackIfMatch,
+		ipOption:      toIPOption(config.QueryStrategy),
+		hosts:         hosts,
+		clients:       clients,
+		ctx:           ctx,
+		clientTags:    clientTags,
+		domainMatcher: domainMatcher,
+		matcherInfos:  matcherInfos,
 	}, nil
 }
 
+func establishDomainRules(config *Config, clients []*Client, nsClientMap map[int]int) (strmatcher.IndexMatcher, []DomainMatcherInfo, error) {
+	domainRuleCount := 0
+	for _, ns := range config.NameServer {
+		domainRuleCount += len(ns.PrioritizedDomain)
+	}
+	// MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1
+	matcherInfos := make([]DomainMatcherInfo, domainRuleCount+1)
+	domainMatcher := &strmatcher.LinearIndexMatcher{}
+	for nsIdx, ns := range config.NameServer {
+		clientIdx := nsClientMap[nsIdx]
+		var rules []string
+		ruleCurr := 0
+		ruleIter := 0
+		for _, domain := range ns.PrioritizedDomain {
+			domainRule, err := toStrMatcher(domain.Type, domain.Domain)
+			if err != nil {
+				return nil, nil, newError("failed to create prioritized domain").Base(err).AtWarning()
+			}
+			originalRuleIdx := ruleCurr
+			if ruleCurr < len(ns.OriginalRules) {
+				rule := ns.OriginalRules[ruleCurr]
+				if ruleCurr >= len(rules) {
+					rules = append(rules, rule.Rule)
+				}
+				ruleIter++
+				if ruleIter >= int(rule.Size) {
+					ruleIter = 0
+					ruleCurr++
+				}
+			} else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests)
+				rules = append(rules, domainRule.String())
+				ruleCurr++
+			}
+			midx := domainMatcher.Add(domainRule)
+			matcherInfos[midx] = DomainMatcherInfo{
+				clientIdx:     uint16(clientIdx),
+				domainRuleIdx: uint16(originalRuleIdx),
+			}
+			if err != nil {
+				return nil, nil, newError("failed to create prioritized domain").Base(err).AtWarning()
+			}
+		}
+		clients[clientIdx].domains = rules
+	}
+	return domainMatcher, matcherInfos, nil
+}
+
+func establishExpectedIPs(config *Config, clients []*Client, nsClientMap map[int]int) error {
+	geoipContainer := router.GeoIPMatcherContainer{}
+	for nsIdx, ns := range config.NameServer {
+		clientIdx := nsClientMap[nsIdx]
+		var matchers []*router.GeoIPMatcher
+		for _, geoip := range ns.Geoip {
+			matcher, err := geoipContainer.Add(geoip)
+			if err != nil {
+				return newError("failed to create ip matcher").Base(err).AtWarning()
+			}
+			matchers = append(matchers, matcher)
+		}
+		clients[clientIdx].expectIPs = matchers
+	}
+	return nil
+}
+
 // Type implements common.HasType.
 func (*DNS) Type() interface{} {
 	return dns.ClientType()
@@ -170,32 +184,28 @@ func (s *DNS) Close() error {
 // IsOwnLink implements proxy.dns.ownLinkVerifier
 func (s *DNS) IsOwnLink(ctx context.Context) bool {
 	inbound := session.InboundFromContext(ctx)
-	return inbound != nil && inbound.Tag == s.tag
+	return inbound != nil && s.clientTags[inbound.Tag]
 }
 
 // LookupIP implements dns.Client.
 func (s *DNS) LookupIP(domain string) ([]net.IP, error) {
-	return s.lookupIPInternal(domain, *s.ipOption)
+	return s.lookupIPInternal(domain, s.ipOption)
 }
 
 // LookupIPv4 implements dns.IPv4Lookup.
 func (s *DNS) LookupIPv4(domain string) ([]net.IP, error) {
-	if !s.ipOption.IPv4Enable {
-		return nil, dns.ErrEmptyResponse
+	if option := s.ipOption.With(dns.IPOption{IPv4Enable: true}); option.IsValid() {
+		return s.lookupIPInternal(domain, option)
 	}
-	o := *s.ipOption
-	o.IPv6Enable = false
-	return s.lookupIPInternal(domain, o)
+	return nil, dns.ErrEmptyResponse
 }
 
 // LookupIPv6 implements dns.IPv6Lookup.
 func (s *DNS) LookupIPv6(domain string) ([]net.IP, error) {
-	if !s.ipOption.IPv6Enable {
-		return nil, dns.ErrEmptyResponse
+	if option := s.ipOption.With(dns.IPOption{IPv6Enable: true}); option.IsValid() {
+		return s.lookupIPInternal(domain, option)
 	}
-	o := *s.ipOption
-	o.IPv4Enable = false
-	return s.lookupIPInternal(domain, o)
+	return nil, dns.ErrEmptyResponse
 }
 
 func (s *DNS) lookupIPInternal(domain string, option dns.IPOption) ([]net.IP, error) {
@@ -222,22 +232,19 @@ func (s *DNS) lookupIPInternal(domain string, option dns.IPOption) ([]net.IP, er
 
 	// Name servers lookup
 	errs := []error{}
-	ctx := session.ContextWithInbound(s.ctx, &session.Inbound{Tag: s.tag})
-	for _, client := range s.sortClients(domain) {
-		if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
-			newError("skip DNS resolution for domain ", domain, " at server ", client.Name()).AtDebug().WriteToLog()
-			continue
-		}
-		ips, err := client.QueryIP(ctx, domain, option, s.disableCache)
+	for _, client := range s.sortClients(domain, option) {
+		ips, err := client.QueryIP(s.ctx, domain, option)
 		if len(ips) > 0 {
 			return ips, nil
 		}
 		if err != nil {
-			newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog()
 			errs = append(errs, err)
 		}
+		if err != dns.ErrEmptyResponse { // ErrEmptyResponse is not seen as failure, so no failed log
+			newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog()
+		}
 		if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch {
-			return nil, err
+			return nil, err // Continues lookup for certain errors
 		}
 	}
 
@@ -246,7 +253,7 @@ func (s *DNS) lookupIPInternal(domain string, option dns.IPOption) ([]net.IP, er
 
 // GetIPOption implements ClientWithIPOption.
 func (s *DNS) GetIPOption() *dns.IPOption {
-	return s.ipOption
+	return &s.ipOption
 }
 
 // SetQueryOption implements ClientWithIPOption.
@@ -260,51 +267,52 @@ func (s *DNS) SetFakeDNSOption(isFakeEnable bool) {
 	s.ipOption.FakeEnable = isFakeEnable
 }
 
-func (s *DNS) sortClients(domain string) []*Client {
+func (s *DNS) sortClients(domain string, option dns.IPOption) []*Client {
 	clients := make([]*Client, 0, len(s.clients))
 	clientUsed := make([]bool, len(s.clients))
 	clientNames := make([]string, 0, len(s.clients))
 	domainRules := []string{}
 
 	// Priority domain matching
-	hasMatch := false
 	for _, match := range s.domainMatcher.Match(domain) {
 		info := s.matcherInfos[match]
 		client := s.clients[info.clientIdx]
 		domainRule := client.domains[info.domainRuleIdx]
 		domainRules = append(domainRules, fmt.Sprintf("%s(DNS idx:%d)", domainRule, info.clientIdx))
-		if clientUsed[info.clientIdx] {
+		switch {
+		case clientUsed[info.clientIdx]:
+			continue
+		case !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS"):
 			continue
 		}
 		clientUsed[info.clientIdx] = true
 		clients = append(clients, client)
 		clientNames = append(clientNames, client.Name())
-		hasMatch = true
 	}
 
-	if !(s.disableFallback || s.disableFallbackIfMatch && hasMatch) {
-		// Default round-robin query
-		for idx, client := range s.clients {
-			if clientUsed[idx] || client.skipFallback {
-				continue
-			}
-			clientUsed[idx] = true
-			clients = append(clients, client)
-			clientNames = append(clientNames, client.Name())
+	// Default round-robin query
+	hasDomainMatch := len(clients) > 0
+	for idx, client := range s.clients {
+		switch {
+		case clientUsed[idx]:
+			continue
+		case !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS"):
+			continue
+		case client.fallbackStrategy == FallbackStrategy_Disabled:
+			continue
+		case client.fallbackStrategy == FallbackStrategy_DisabledIfAnyMatch && hasDomainMatch:
+			continue
 		}
+		clientUsed[idx] = true
+		clients = append(clients, client)
+		clientNames = append(clientNames, client.Name())
 	}
 
 	if len(domainRules) > 0 {
 		newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog()
 	}
 	if len(clientNames) > 0 {
-		newError("domain ", domain, " will use DNS in order: ", clientNames).AtDebug().WriteToLog()
-	}
-
-	if len(clients) == 0 {
-		clients = append(clients, s.clients[0])
-		clientNames = append(clientNames, s.clients[0].Name())
-		newError("domain ", domain, " will use the first DNS: ", clientNames).AtDebug().WriteToLog()
+		newError("domain ", domain, " will use DNS in order: ", clientNames, " ", toReqTypes(option)).AtDebug().WriteToLog()
 	}
 
 	return clients
@@ -354,10 +362,14 @@ func init() {
 
 		for _, v := range simplifiedConfig.NameServer {
 			nameserver := &NameServer{
-				Address:      v.Address,
-				ClientIp:     net.ParseIP(v.ClientIp),
-				SkipFallback: v.SkipFallback,
-				Geoip:        v.Geoip,
+				Address:          v.Address,
+				ClientIp:         net.ParseIP(v.ClientIp),
+				Tag:              v.Tag,
+				QueryStrategy:    v.QueryStrategy,
+				CacheStrategy:    v.CacheStrategy,
+				FallbackStrategy: v.FallbackStrategy,
+				SkipFallback:     v.SkipFallback,
+				Geoip:            v.Geoip,
 			}
 			for _, prioritizedDomain := range v.PrioritizedDomain {
 				nameserver.PrioritizedDomain = append(nameserver.PrioritizedDomain, &NameServer_PriorityDomain{
@@ -369,13 +381,17 @@ func init() {
 		}
 
 		fullConfig := &Config{
-			NameServer:      nameservers,
-			ClientIp:        net.ParseIP(simplifiedConfig.ClientIp),
-			StaticHosts:     simplifiedConfig.StaticHosts,
-			Tag:             simplifiedConfig.Tag,
-			DisableCache:    simplifiedConfig.DisableCache,
-			QueryStrategy:   simplifiedConfig.QueryStrategy,
-			DisableFallback: simplifiedConfig.DisableFallback,
+			StaticHosts:      simplifiedConfig.StaticHosts,
+			NameServer:       nameservers,
+			ClientIp:         net.ParseIP(simplifiedConfig.ClientIp),
+			Tag:              simplifiedConfig.Tag,
+			QueryStrategy:    simplifiedConfig.QueryStrategy,
+			CacheStrategy:    simplifiedConfig.CacheStrategy,
+			FallbackStrategy: simplifiedConfig.FallbackStrategy,
+			// Deprecated flags
+			DisableCache:           simplifiedConfig.DisableCache,
+			DisableFallback:        simplifiedConfig.DisableFallback,
+			DisableFallbackIfMatch: simplifiedConfig.DisableFallbackIfMatch,
 		}
 		return common.CreateObject(ctx, fullConfig)
 	}))

+ 79 - 103
app/dns/nameserver.go

@@ -10,7 +10,8 @@ import (
 	"github.com/v2fly/v2ray-core/v5/app/router"
 	"github.com/v2fly/v2ray-core/v5/common/errors"
 	"github.com/v2fly/v2ray-core/v5/common/net"
-	"github.com/v2fly/v2ray-core/v5/common/strmatcher"
+	"github.com/v2fly/v2ray-core/v5/common/session"
+	"github.com/v2fly/v2ray-core/v5/features"
 	"github.com/v2fly/v2ray-core/v5/features/dns"
 	"github.com/v2fly/v2ray-core/v5/features/routing"
 )
@@ -25,11 +26,16 @@ type Server interface {
 
 // Client is the interface for DNS client.
 type Client struct {
-	server       Server
-	clientIP     net.IP
-	skipFallback bool
-	domains      []string
-	expectIPs    []*router.GeoIPMatcher
+	server   Server
+	clientIP net.IP
+	tag      string
+
+	queryStrategy    dns.IPOption
+	cacheStrategy    CacheStrategy
+	fallbackStrategy FallbackStrategy
+
+	domains   []string
+	expectIPs []*router.GeoIPMatcher
 }
 
 var errExpectedIPNonMatch = errors.New("expectIPs not match")
@@ -68,117 +74,79 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, err
 }
 
 // NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
-func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container router.GeoIPMatcherContainer, matcherInfos *[]DomainMatcherInfo, updateDomainRule func(strmatcher.Matcher, int, []DomainMatcherInfo) error) (*Client, error) {
+func NewClient(ctx context.Context, ns *NameServer, dns *Config) (*Client, error) {
 	client := &Client{}
 
+	// 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()
 		}
-
-		// Priotize local domains with specific TLDs or without any dot to local DNS
-		if _, isLocalDNS := server.(*LocalNameServer); isLocalDNS {
-			ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...)
-			ns.OriginalRules = append(ns.OriginalRules, localTLDsAndDotlessDomainsRule)
-			// The following lines is a solution to avoid core panics(rule index out of range) when setting `localhost` DNS client in config.
-			// Because the `localhost` DNS client will apend len(localTLDsAndDotlessDomains) rules into matcherInfos to match `geosite:private` default rule.
-			// But `matcherInfos` has no enough length to add rules, which leads to core panics (rule index out of range).
-			// To avoid this, the length of `matcherInfos` must be equal to the expected, so manually append it with Golang default zero value first for later modification.
-			// Related issues:
-			// https://github.com/v2fly/v2ray-core/issues/529
-			// https://github.com/v2fly/v2ray-core/issues/719
-			for i := 0; i < len(localTLDsAndDotlessDomains); i++ {
-				*matcherInfos = append(*matcherInfos, DomainMatcherInfo{
-					clientIdx:     uint16(0),
-					domainRuleIdx: uint16(0),
-				})
-			}
-		}
-
-		// Establish domain rules
-		var rules []string
-		ruleCurr := 0
-		ruleIter := 0
-		for _, domain := range ns.PrioritizedDomain {
-			domainRule, err := toStrMatcher(domain.Type, domain.Domain)
-			if err != nil {
-				return newError("failed to create prioritized domain").Base(err).AtWarning()
-			}
-			originalRuleIdx := ruleCurr
-			if ruleCurr < len(ns.OriginalRules) {
-				rule := ns.OriginalRules[ruleCurr]
-				if ruleCurr >= len(rules) {
-					rules = append(rules, rule.Rule)
-				}
-				ruleIter++
-				if ruleIter >= int(rule.Size) {
-					ruleIter = 0
-					ruleCurr++
-				}
-			} else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests)
-				rules = append(rules, domainRule.String())
-				ruleCurr++
-			}
-			err = updateDomainRule(domainRule, originalRuleIdx, *matcherInfos)
-			if err != nil {
-				return newError("failed to create prioritized domain").Base(err).AtWarning()
-			}
-		}
-
-		// Establish expected IPs
-		var matchers []*router.GeoIPMatcher
-		for _, geoip := range ns.Geoip {
-			matcher, err := container.Add(geoip)
-			if err != nil {
-				return newError("failed to create ip matcher").Base(err).AtWarning()
-			}
-			matchers = append(matchers, matcher)
-		}
-
-		if len(clientIP) > 0 {
-			switch ns.Address.Address.GetAddress().(type) {
-			case *net.IPOrDomain_Domain:
-				newError("DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
-			case *net.IPOrDomain_Ip:
-				newError("DNS: client ", ns.Address.Address.GetIp(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
-			}
-		}
-
 		client.server = server
-		client.clientIP = clientIP
-		client.skipFallback = ns.SkipFallback
-		client.domains = rules
-		client.expectIPs = matchers
 		return nil
 	})
-	return client, err
-}
+	if err != nil {
+		return nil, err
+	}
 
-// NewSimpleClient creates a DNS client with a simple destination.
-func NewSimpleClient(ctx context.Context, endpoint *net.Endpoint, clientIP net.IP) (*Client, error) {
-	client := &Client{}
-	err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
-		server, err := NewServer(endpoint.AsDestination(), dispatcher)
-		if err != nil {
-			return newError("failed to create nameserver").Base(err).AtWarning()
+	// Initialize fields with default values
+	if len(ns.Tag) == 0 {
+		ns.Tag = dns.Tag
+		if len(ns.Tag) == 0 {
+			ns.Tag = generateRandomTag()
 		}
-		client.server = server
-		client.clientIP = clientIP
-		return nil
-	})
-
-	if len(clientIP) > 0 {
-		switch endpoint.Address.GetAddress().(type) {
-		case *net.IPOrDomain_Domain:
-			newError("DNS: client ", endpoint.Address.GetDomain(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
-		case *net.IPOrDomain_Ip:
-			newError("DNS: client ", endpoint.Address.GetIp(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog()
+	}
+	if len(ns.ClientIp) == 0 {
+		ns.ClientIp = dns.ClientIp
+	}
+	if ns.QueryStrategy == nil {
+		ns.QueryStrategy = &dns.QueryStrategy
+	}
+	if ns.CacheStrategy == nil {
+		ns.CacheStrategy = new(CacheStrategy)
+		switch {
+		case dns.CacheStrategy != CacheStrategy_CacheEnabled:
+			*ns.CacheStrategy = dns.CacheStrategy
+		case dns.DisableCache:
+			features.PrintDeprecatedFeatureWarning("DNS disableCache settings")
+			*ns.CacheStrategy = CacheStrategy_CacheDisabled
 		}
 	}
+	if ns.FallbackStrategy == nil {
+		ns.FallbackStrategy = new(FallbackStrategy)
+		switch {
+		case ns.SkipFallback:
+			features.PrintDeprecatedFeatureWarning("DNS server skipFallback settings")
+			*ns.FallbackStrategy = FallbackStrategy_Disabled
+		case dns.FallbackStrategy != FallbackStrategy_Enabled:
+			*ns.FallbackStrategy = dns.FallbackStrategy
+		case dns.DisableFallback:
+			features.PrintDeprecatedFeatureWarning("DNS disableFallback settings")
+			*ns.FallbackStrategy = FallbackStrategy_Disabled
+		case dns.DisableFallbackIfMatch:
+			features.PrintDeprecatedFeatureWarning("DNS disableFallbackIfMatch settings")
+			*ns.FallbackStrategy = FallbackStrategy_DisabledIfAnyMatch
+		}
+	}
+
+	// Priotize local domains with specific TLDs or without any dot to local DNS
+	if strings.EqualFold(ns.Address.Address.GetDomain(), "localhost") {
+		ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...)
+		ns.OriginalRules = append(ns.OriginalRules, localTLDsAndDotlessDomainsRule)
+	}
+
+	if len(ns.ClientIp) > 0 {
+		newError("DNS: client ", ns.Address.Address.AsAddress(), " uses clientIP ", net.IP(ns.ClientIp).String()).AtInfo().WriteToLog()
+	}
 
-	return client, err
+	client.clientIP = ns.ClientIp
+	client.tag = ns.Tag
+	client.queryStrategy = toIPOption(*ns.QueryStrategy)
+	client.cacheStrategy = *ns.CacheStrategy
+	client.fallbackStrategy = *ns.FallbackStrategy
+	return client, nil
 }
 
 // Name returns the server name the client manages.
@@ -187,9 +155,17 @@ func (c *Client) Name() string {
 }
 
 // QueryIP send DNS query to the name server with the client's IP.
-func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption, disableCache bool) ([]net.IP, error) {
+func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, error) {
+	queryOption := option.With(c.queryStrategy)
+	if !queryOption.IsValid() {
+		newError(c.server.Name(), " returns empty answer: ", domain, ". ", toReqTypes(option)).AtInfo().WriteToLog()
+		return nil, dns.ErrEmptyResponse
+	}
+	disableCache := c.cacheStrategy == CacheStrategy_CacheDisabled
+
+	ctx = session.ContextWithInbound(ctx, &session.Inbound{Tag: c.tag})
 	ctx, cancel := context.WithTimeout(ctx, 4*time.Second)
-	ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option, disableCache)
+	ips, err := c.server.QueryIP(ctx, domain, c.clientIP, queryOption, disableCache)
 	cancel()
 
 	if err != nil {

+ 12 - 0
features/dns/client.go

@@ -14,6 +14,18 @@ type IPOption struct {
 	FakeEnable bool
 }
 
+func (opt IPOption) With(other IPOption) IPOption {
+	return IPOption{
+		IPv4Enable: opt.IPv4Enable && other.IPv4Enable,
+		IPv6Enable: opt.IPv6Enable && other.IPv6Enable,
+		FakeEnable: opt.FakeEnable && other.FakeEnable,
+	}
+}
+
+func (opt IPOption) IsValid() bool {
+	return opt.IPv4Enable || opt.IPv6Enable
+}
+
 // Client is a V2Ray feature for querying DNS information.
 //
 // v2ray:api:stable

+ 82 - 12
infra/conf/synthetic/dns/dns.go

@@ -18,12 +18,16 @@ import (
 )
 
 type NameServerConfig struct {
-	Address      *cfgcommon.Address
-	ClientIP     *cfgcommon.Address
-	Port         uint16
-	SkipFallback bool
-	Domains      []string
-	ExpectIPs    cfgcommon.StringList
+	Address          *cfgcommon.Address
+	ClientIP         *cfgcommon.Address
+	Port             uint16
+	Tag              string
+	QueryStrategy    string
+	CacheStrategy    string
+	FallbackStrategy string
+	SkipFallback     bool
+	Domains          []string
+	ExpectIPs        cfgcommon.StringList
 
 	cfgctx context.Context
 }
@@ -36,17 +40,25 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
 	}
 
 	var advanced struct {
-		Address      *cfgcommon.Address   `json:"address"`
-		ClientIP     *cfgcommon.Address   `json:"clientIp"`
-		Port         uint16               `json:"port"`
-		SkipFallback bool                 `json:"skipFallback"`
-		Domains      []string             `json:"domains"`
-		ExpectIPs    cfgcommon.StringList `json:"expectIps"`
+		Address          *cfgcommon.Address   `json:"address"`
+		ClientIP         *cfgcommon.Address   `json:"clientIp"`
+		Port             uint16               `json:"port"`
+		Tag              string               `json:"tag"`
+		QueryStrategy    string               `json:"queryStrategy"`
+		CacheStrategy    string               `json:"cacheStrategy"`
+		FallbackStrategy string               `json:"fallbackStrategy"`
+		SkipFallback     bool                 `json:"skipFallback"`
+		Domains          []string             `json:"domains"`
+		ExpectIPs        cfgcommon.StringList `json:"expectIps"`
 	}
 	if err := json.Unmarshal(data, &advanced); err == nil {
 		c.Address = advanced.Address
 		c.ClientIP = advanced.ClientIP
 		c.Port = advanced.Port
+		c.Tag = advanced.Tag
+		c.QueryStrategy = advanced.QueryStrategy
+		c.CacheStrategy = advanced.CacheStrategy
+		c.FallbackStrategy = advanced.FallbackStrategy
 		c.SkipFallback = advanced.SkipFallback
 		c.Domains = advanced.Domains
 		c.ExpectIPs = advanced.ExpectIPs
@@ -117,6 +129,40 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
 		myClientIP = []byte(c.ClientIP.IP())
 	}
 
+	queryStrategy := new(dns.QueryStrategy)
+	switch strings.ToLower(c.QueryStrategy) {
+	case "useip", "use_ip", "use-ip":
+		*queryStrategy = dns.QueryStrategy_USE_IP
+	case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4":
+		*queryStrategy = dns.QueryStrategy_USE_IP4
+	case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6":
+		*queryStrategy = dns.QueryStrategy_USE_IP6
+	default:
+		queryStrategy = nil
+	}
+
+	cacheStrategy := new(dns.CacheStrategy)
+	switch strings.ToLower(c.CacheStrategy) {
+	case "enabled":
+		*cacheStrategy = dns.CacheStrategy_CacheEnabled
+	case "disabled":
+		*cacheStrategy = dns.CacheStrategy_CacheDisabled
+	default:
+		cacheStrategy = nil
+	}
+
+	fallbackStrategy := new(dns.FallbackStrategy)
+	switch strings.ToLower(c.FallbackStrategy) {
+	case "enabled":
+		*fallbackStrategy = dns.FallbackStrategy_Enabled
+	case "disabled":
+		*fallbackStrategy = dns.FallbackStrategy_Disabled
+	case "disabledifanymatch", "disabled_if_any_match", "disabled-if-any-match":
+		*fallbackStrategy = dns.FallbackStrategy_DisabledIfAnyMatch
+	default:
+		fallbackStrategy = nil
+	}
+
 	return &dns.NameServer{
 		Address: &net.Endpoint{
 			Network: net.Network_UDP,
@@ -124,7 +170,11 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
 			Port:    uint32(c.Port),
 		},
 		ClientIp:          myClientIP,
+		Tag:               c.Tag,
 		SkipFallback:      c.SkipFallback,
+		QueryStrategy:     queryStrategy,
+		CacheStrategy:     cacheStrategy,
+		FallbackStrategy:  fallbackStrategy,
 		PrioritizedDomain: domains,
 		Geoip:             geoipList,
 		OriginalRules:     originalRules,
@@ -145,6 +195,8 @@ type DNSConfig struct { // nolint: revive
 	ClientIP               *cfgcommon.Address      `json:"clientIp"`
 	Tag                    string                  `json:"tag"`
 	QueryStrategy          string                  `json:"queryStrategy"`
+	CacheStrategy          string                  `json:"cacheStrategy"`
+	FallbackStrategy       string                  `json:"fallbackStrategy"`
 	DisableCache           bool                    `json:"disableCache"`
 	DisableFallback        bool                    `json:"disableFallback"`
 	DisableFallbackIfMatch bool                    `json:"disableFallbackIfMatch"`
@@ -245,6 +297,24 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
 		config.QueryStrategy = dns.QueryStrategy_USE_IP6
 	}
 
+	config.CacheStrategy = dns.CacheStrategy_CacheEnabled
+	switch strings.ToLower(c.CacheStrategy) {
+	case "enabled":
+		config.CacheStrategy = dns.CacheStrategy_CacheEnabled
+	case "disabled":
+		config.CacheStrategy = dns.CacheStrategy_CacheDisabled
+	}
+
+	config.FallbackStrategy = dns.FallbackStrategy_Enabled
+	switch strings.ToLower(c.FallbackStrategy) {
+	case "enabled":
+		config.FallbackStrategy = dns.FallbackStrategy_Enabled
+	case "disabled":
+		config.FallbackStrategy = dns.FallbackStrategy_Disabled
+	case "disabledifanymatch", "disabled_if_any_match", "disabled-if-any-match":
+		config.FallbackStrategy = dns.FallbackStrategy_DisabledIfAnyMatch
+	}
+
 	for _, server := range c.Servers {
 		server.cfgctx = c.cfgctx
 		ns, err := server.Build()