1
0
Эх сурвалжийг харах

Some refines related to direct/freedom and `targetStrategy`; More intelligent "useIP"/"ForceIP", enhance "origin" functionality (#5030)

https://github.com/XTLS/Xray-core/pull/5009#issuecomment-3194264277
patterniha 4 сар өмнө
parent
commit
6d1695a686

+ 9 - 1
app/proxyman/inbound/worker.go

@@ -322,10 +322,18 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
 				outbounds[0].Target = originalDest
 			}
 			ctx = session.ContextWithOutbounds(ctx, outbounds)
+			local := net.DestinationFromAddr(w.hub.Addr())
+			if local.Address == net.AnyIP || local.Address == net.AnyIPv6 {
+				if source.Address.Family().IsIPv4() {
+					local.Address = net.AnyIP
+				} else if source.Address.Family().IsIPv6() {
+					local.Address = net.AnyIPv6
+				}
+			}
 
 			ctx = session.ContextWithInbound(ctx, &session.Inbound{
 				Source:  source,
-				Local:   net.DestinationFromAddr(w.hub.Addr()), // Due to some limitations, in UDP connections, localIP is always equal to listen interface IP
+				Local:   local, // Due to some limitations, in UDP connections, localIP is always equal to listen interface IP
 				Gateway: net.UDPDestination(w.address, w.port),
 				Tag:     w.tag,
 			})

+ 43 - 39
app/proxyman/outbound/handler.go

@@ -4,12 +4,13 @@ import (
 	"context"
 	"crypto/rand"
 	goerrors "errors"
-	"github.com/xtls/xray-core/common/dice"
 	"io"
 	"math/big"
 	gonet "net"
 	"os"
 
+	"github.com/xtls/xray-core/common/dice"
+
 	"github.com/xtls/xray-core/app/proxyman"
 	"github.com/xtls/xray-core/common"
 	"github.com/xtls/xray-core/common/buf"
@@ -180,7 +181,11 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
 	ob := outbounds[len(outbounds)-1]
 	content := session.ContentFromContext(ctx)
 	if h.senderSettings != nil && h.senderSettings.TargetStrategy.HasStrategy() && ob.Target.Address.Family().IsDomain() && (content == nil || !content.SkipDNSResolve) {
-		ips, err := internet.LookupForIP(ob.Target.Address.Domain(), h.senderSettings.TargetStrategy, nil)
+		strategy := h.senderSettings.TargetStrategy
+		if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil {
+			strategy = strategy.GetDynamicStrategy(ob.OriginalTarget.Address.Family())
+		}
+		ips, err := internet.LookupForIP(ob.Target.Address.Domain(), strategy, nil)
 		if err != nil {
 			errors.LogInfoInner(ctx, err, "failed to resolve ip for target ", ob.Target.Address.Domain())
 			if h.senderSettings.TargetStrategy.ForceIP() {
@@ -251,14 +256,6 @@ out:
 	common.Interrupt(link.Reader)
 }
 
-// Address implements internet.Dialer.
-func (h *Handler) Address() net.Address {
-	if h.senderSettings == nil || h.senderSettings.Via == nil {
-		return nil
-	}
-	return h.senderSettings.Via.AsAddress()
-}
-
 func (h *Handler) DestIpAddress() net.IP {
 	return internet.DestIpAddress()
 }
@@ -293,41 +290,16 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
 				return h.getStatCouterConnection(conn), nil
 			}
 
-			errors.LogWarning(ctx, "failed to get outbound handler with tag: ", tag)
+			errors.LogError(ctx, "failed to get outbound handler with tag: ", tag)
+			return nil, errors.New("failed to get outbound handler with tag: " + tag)
 		}
 
 		if h.senderSettings.Via != nil {
-
 			outbounds := session.OutboundsFromContext(ctx)
 			ob := outbounds[len(outbounds)-1]
-			var domain string
-			addr := h.senderSettings.Via.AsAddress()
-			domain = h.senderSettings.Via.GetDomain()
-			switch {
-			case h.senderSettings.ViaCidr != "":
-				ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
-
-			case domain == "origin":
-				if inbound := session.InboundFromContext(ctx); inbound != nil {
-					if inbound.Local.IsValid() && inbound.Local.Address.Family().IsIP() {
-						ob.Gateway = inbound.Local.Address
-						errors.LogDebug(ctx, "use inbound local ip as sendthrough: ", inbound.Local.Address.String())
-					}
-				}
-			case domain == "srcip":
-				if inbound := session.InboundFromContext(ctx); inbound != nil {
-					if inbound.Source.IsValid() && inbound.Source.Address.Family().IsIP() {
-						ob.Gateway = inbound.Source.Address
-						errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String())
-					}
-				}
-			//case addr.Family().IsDomain():
-			default:
-				ob.Gateway = addr
-
-			}
-
+			h.SetOutboundGateway(ctx, ob)
 		}
+
 	}
 
 	if conn, err := h.getUoTConnection(ctx, dest); err != os.ErrInvalid {
@@ -342,6 +314,38 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
 	return conn, err
 }
 
+func (h *Handler) SetOutboundGateway(ctx context.Context, ob *session.Outbound) {
+	if ob.Gateway == nil && h.senderSettings != nil && h.senderSettings.Via != nil && !h.senderSettings.ProxySettings.HasTag() && (h.streamSettings.SocketSettings == nil || len(h.streamSettings.SocketSettings.DialerProxy) == 0) {
+		var domain string
+		addr := h.senderSettings.Via.AsAddress()
+		domain = h.senderSettings.Via.GetDomain()
+		switch {
+		case h.senderSettings.ViaCidr != "":
+			ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
+
+		case domain == "origin":
+			if inbound := session.InboundFromContext(ctx); inbound != nil {
+				if inbound.Local.IsValid() && inbound.Local.Address.Family().IsIP() {
+					ob.Gateway = inbound.Local.Address
+					errors.LogDebug(ctx, "use inbound local ip as sendthrough: ", inbound.Local.Address.String())
+				}
+			}
+		case domain == "srcip":
+			if inbound := session.InboundFromContext(ctx); inbound != nil {
+				if inbound.Source.IsValid() && inbound.Source.Address.Family().IsIP() {
+					ob.Gateway = inbound.Source.Address
+					errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String())
+				}
+			}
+		//case addr.Family().IsDomain():
+		default:
+			ob.Gateway = addr
+
+		}
+
+	}
+}
+
 func (h *Handler) getStatCouterConnection(conn stat.Connection) stat.Connection {
 	if h.uplinkCounter != nil || h.downlinkCounter != nil {
 		return &stat.CounterConnection{

+ 12 - 11
infra/conf/freedom.go

@@ -11,6 +11,7 @@ import (
 	"github.com/xtls/xray-core/common/protocol"
 	"github.com/xtls/xray-core/proxy/freedom"
 	"google.golang.org/protobuf/proto"
+	"github.com/xtls/xray-core/transport/internet"
 )
 
 type FreedomConfig struct {
@@ -47,27 +48,27 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
 	}
 	switch strings.ToLower(targetStrategy) {
 	case "asis", "":
-		config.DomainStrategy = freedom.Config_AS_IS
+		config.DomainStrategy = internet.DomainStrategy_AS_IS
 	case "useip":
-		config.DomainStrategy = freedom.Config_USE_IP
+		config.DomainStrategy = internet.DomainStrategy_USE_IP
 	case "useipv4":
-		config.DomainStrategy = freedom.Config_USE_IP4
+		config.DomainStrategy = internet.DomainStrategy_USE_IP4
 	case "useipv6":
-		config.DomainStrategy = freedom.Config_USE_IP6
+		config.DomainStrategy = internet.DomainStrategy_USE_IP6
 	case "useipv4v6":
-		config.DomainStrategy = freedom.Config_USE_IP46
+		config.DomainStrategy = internet.DomainStrategy_USE_IP46
 	case "useipv6v4":
-		config.DomainStrategy = freedom.Config_USE_IP64
+		config.DomainStrategy = internet.DomainStrategy_USE_IP64
 	case "forceip":
-		config.DomainStrategy = freedom.Config_FORCE_IP
+		config.DomainStrategy = internet.DomainStrategy_FORCE_IP
 	case "forceipv4":
-		config.DomainStrategy = freedom.Config_FORCE_IP4
+		config.DomainStrategy = internet.DomainStrategy_FORCE_IP4
 	case "forceipv6":
-		config.DomainStrategy = freedom.Config_FORCE_IP6
+		config.DomainStrategy = internet.DomainStrategy_FORCE_IP6
 	case "forceipv4v6":
-		config.DomainStrategy = freedom.Config_FORCE_IP46
+		config.DomainStrategy = internet.DomainStrategy_FORCE_IP46
 	case "forceipv6v4":
-		config.DomainStrategy = freedom.Config_FORCE_IP64
+		config.DomainStrategy = internet.DomainStrategy_FORCE_IP64
 	default:
 		return nil, errors.New("unsupported domain strategy: ", targetStrategy)
 	}

+ 2 - 1
infra/conf/freedom_test.go

@@ -7,6 +7,7 @@ import (
 	"github.com/xtls/xray-core/common/protocol"
 	. "github.com/xtls/xray-core/infra/conf"
 	"github.com/xtls/xray-core/proxy/freedom"
+	"github.com/xtls/xray-core/transport/internet"
 )
 
 func TestFreedomConfig(t *testing.T) {
@@ -23,7 +24,7 @@ func TestFreedomConfig(t *testing.T) {
 			}`,
 			Parser: loadJSON(creator),
 			Output: &freedom.Config{
-				DomainStrategy: freedom.Config_AS_IS,
+				DomainStrategy: internet.DomainStrategy_AS_IS,
 				DestinationOverride: &freedom.DestinationOverride{
 					Server: &protocol.ServerEndpoint{
 						Address: &net.IPOrDomain{

+ 0 - 43
proxy/freedom/config.go

@@ -1,44 +1 @@
 package freedom
-
-var strategy = [][]byte{
-	//              name        strategy,   prefer, fallback
-	{0, 0, 0}, //   AsIs        none,       /,      /
-	{1, 0, 0}, //   UseIP       use,        both,   none
-	{1, 4, 0}, //   UseIPv4     use,        4,      none
-	{1, 6, 0}, //   UseIPv6     use,        6,      none
-	{1, 4, 6}, //   UseIPv4v6   use,        4,      6
-	{1, 6, 4}, //   UseIPv6v4   use,        6,      4
-	{2, 0, 0}, //   ForceIP     force,      both,   none
-	{2, 4, 0}, //   ForceIPv4   force,      4,      none
-	{2, 6, 0}, //   ForceIPv6   force,      6,      none
-	{2, 4, 6}, //   ForceIPv4v6 force,      4,      6
-	{2, 6, 4}, //   ForceIPv6v4 force,      6,      4
-}
-
-func (c *Config) hasStrategy() bool {
-	return strategy[c.DomainStrategy][0] != 0
-}
-
-func (c *Config) forceIP() bool {
-	return strategy[c.DomainStrategy][0] == 2
-}
-
-func (c *Config) preferIP4() bool {
-	return strategy[c.DomainStrategy][1] == 4 || strategy[c.DomainStrategy][1] == 0
-}
-
-func (c *Config) preferIP6() bool {
-	return strategy[c.DomainStrategy][1] == 6 || strategy[c.DomainStrategy][1] == 0
-}
-
-func (c *Config) hasFallback() bool {
-	return strategy[c.DomainStrategy][2] != 0
-}
-
-func (c *Config) fallbackIP4() bool {
-	return strategy[c.DomainStrategy][2] == 4
-}
-
-func (c *Config) fallbackIP6() bool {
-	return strategy[c.DomainStrategy][2] == 6
-}

+ 87 - 170
proxy/freedom/config.pb.go

@@ -8,6 +8,7 @@ package freedom
 
 import (
 	protocol "github.com/xtls/xray-core/common/protocol"
+	internet "github.com/xtls/xray-core/transport/internet"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -21,79 +22,6 @@ const (
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-type Config_DomainStrategy int32
-
-const (
-	Config_AS_IS      Config_DomainStrategy = 0
-	Config_USE_IP     Config_DomainStrategy = 1
-	Config_USE_IP4    Config_DomainStrategy = 2
-	Config_USE_IP6    Config_DomainStrategy = 3
-	Config_USE_IP46   Config_DomainStrategy = 4
-	Config_USE_IP64   Config_DomainStrategy = 5
-	Config_FORCE_IP   Config_DomainStrategy = 6
-	Config_FORCE_IP4  Config_DomainStrategy = 7
-	Config_FORCE_IP6  Config_DomainStrategy = 8
-	Config_FORCE_IP46 Config_DomainStrategy = 9
-	Config_FORCE_IP64 Config_DomainStrategy = 10
-)
-
-// Enum value maps for Config_DomainStrategy.
-var (
-	Config_DomainStrategy_name = map[int32]string{
-		0:  "AS_IS",
-		1:  "USE_IP",
-		2:  "USE_IP4",
-		3:  "USE_IP6",
-		4:  "USE_IP46",
-		5:  "USE_IP64",
-		6:  "FORCE_IP",
-		7:  "FORCE_IP4",
-		8:  "FORCE_IP6",
-		9:  "FORCE_IP46",
-		10: "FORCE_IP64",
-	}
-	Config_DomainStrategy_value = map[string]int32{
-		"AS_IS":      0,
-		"USE_IP":     1,
-		"USE_IP4":    2,
-		"USE_IP6":    3,
-		"USE_IP46":   4,
-		"USE_IP64":   5,
-		"FORCE_IP":   6,
-		"FORCE_IP4":  7,
-		"FORCE_IP6":  8,
-		"FORCE_IP46": 9,
-		"FORCE_IP64": 10,
-	}
-)
-
-func (x Config_DomainStrategy) Enum() *Config_DomainStrategy {
-	p := new(Config_DomainStrategy)
-	*p = x
-	return p
-}
-
-func (x Config_DomainStrategy) String() string {
-	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (Config_DomainStrategy) Descriptor() protoreflect.EnumDescriptor {
-	return file_proxy_freedom_config_proto_enumTypes[0].Descriptor()
-}
-
-func (Config_DomainStrategy) Type() protoreflect.EnumType {
-	return &file_proxy_freedom_config_proto_enumTypes[0]
-}
-
-func (x Config_DomainStrategy) Number() protoreflect.EnumNumber {
-	return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Use Config_DomainStrategy.Descriptor instead.
-func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) {
-	return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3, 0}
-}
-
 type DestinationOverride struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -330,12 +258,12 @@ type Config struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	DomainStrategy      Config_DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.proxy.freedom.Config_DomainStrategy" json:"domain_strategy,omitempty"`
-	DestinationOverride *DestinationOverride  `protobuf:"bytes,3,opt,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
-	UserLevel           uint32                `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
-	Fragment            *Fragment             `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"`
-	ProxyProtocol       uint32                `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"`
-	Noises              []*Noise              `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"`
+	DomainStrategy      internet.DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
+	DestinationOverride *DestinationOverride    `protobuf:"bytes,3,opt,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
+	UserLevel           uint32                  `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
+	Fragment            *Fragment               `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"`
+	ProxyProtocol       uint32                  `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"`
+	Noises              []*Noise                `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"`
 }
 
 func (x *Config) Reset() {
@@ -368,11 +296,11 @@ func (*Config) Descriptor() ([]byte, []int) {
 	return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3}
 }
 
-func (x *Config) GetDomainStrategy() Config_DomainStrategy {
+func (x *Config) GetDomainStrategy() internet.DomainStrategy {
 	if x != nil {
 		return x.DomainStrategy
 	}
-	return Config_AS_IS
+	return internet.DomainStrategy(0)
 }
 
 func (x *Config) GetDestinationOverride() *DestinationOverride {
@@ -418,81 +346,72 @@ var file_proxy_freedom_config_proto_rawDesc = []byte{
 	0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d,
 	0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
 	0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72,
-	0x6f, 0x74, 0x6f, 0x22, 0x53, 0x0a, 0x13, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69,
-	0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65,
-	0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61,
-	0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
-	0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
-	0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x98, 0x02, 0x0a, 0x08, 0x46, 0x72, 0x61,
-	0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73,
-	0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x70, 0x61, 0x63,
-	0x6b, 0x65, 0x74, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63, 0x6b,
-	0x65, 0x74, 0x73, 0x5f, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x70, 0x61,
-	0x63, 0x6b, 0x65, 0x74, 0x73, 0x54, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74,
-	0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e,
-	0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68,
-	0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67,
-	0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61,
-	0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e, 0x74,
-	0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65,
-	0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b,
-	0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x61, 0x78, 0x12, 0x22, 0x0a, 0x0d, 0x6d,
-	0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01,
-	0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x4d, 0x69, 0x6e, 0x12,
-	0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x61, 0x78,
-	0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69, 0x74,
-	0x4d, 0x61, 0x78, 0x22, 0xb2, 0x01, 0x0a, 0x05, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x12, 0x1d, 0x0a,
-	0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a,
-	0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x64,
-	0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08,
-	0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x69, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x61,
-	0x79, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x6c,
-	0x61, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x18,
-	0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x19, 0x0a,
-	0x08, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x5f, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x07, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x22, 0x97, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e,
-	0x66, 0x69, 0x67, 0x12, 0x52, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74,
-	0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x78,
-	0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f,
-	0x6d, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53,
-	0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53,
-	0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x5a, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69,
-	0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18,
-	0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
-	0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69,
-	0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x13,
-	0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72,
-	0x69, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65,
-	0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76,
-	0x65, 0x6c, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05,
-	0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78,
-	0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65,
-	0x6e, 0x74, 0x52, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e,
-	0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06,
-	0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f,
-	0x63, 0x6f, 0x6c, 0x12, 0x31, 0x0a, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20,
-	0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
-	0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x52, 0x06,
-	0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
-	0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f,
-	0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01,
-	0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a,
-	0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53,
-	0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f,
-	0x49, 0x50, 0x36, 0x34, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f,
-	0x49, 0x50, 0x10, 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50,
-	0x34, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36,
-	0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36,
-	0x10, 0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34,
-	0x10, 0x0a, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70,
-	0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50, 0x01, 0x5a, 0x27,
-	0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f,
-	0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f,
-	0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50,
-	0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, 0x06, 0x70, 0x72,
-	0x6f, 0x74, 0x6f, 0x33,
+	0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69,
+	0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x22, 0x53, 0x0a, 0x13, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x73,
+	0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72,
+	0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
+	0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x98, 0x02, 0x0a, 0x08, 0x46, 0x72,
+	0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74,
+	0x73, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x70, 0x61,
+	0x63, 0x6b, 0x65, 0x74, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63,
+	0x6b, 0x65, 0x74, 0x73, 0x5f, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x70,
+	0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x54, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67,
+	0x74, 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65,
+	0x6e, 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74,
+	0x68, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e,
+	0x67, 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76,
+	0x61, 0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e,
+	0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74,
+	0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x61, 0x78, 0x12, 0x22, 0x0a, 0x0d,
+	0x6d, 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x07, 0x20,
+	0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x4d, 0x69, 0x6e,
+	0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x61,
+	0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69,
+	0x74, 0x4d, 0x61, 0x78, 0x22, 0xb2, 0x01, 0x0a, 0x05, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x12, 0x1d,
+	0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a,
+	0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a, 0x09,
+	0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x69, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c,
+	0x61, 0x79, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65,
+	0x6c, 0x61, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x19,
+	0x0a, 0x08, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x5f, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x22, 0xe9, 0x02, 0x0a, 0x06, 0x43, 0x6f,
+	0x6e, 0x66, 0x69, 0x67, 0x12, 0x50, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73,
+	0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e,
+	0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69,
+	0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74,
+	0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74,
+	0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x5a, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78,
+	0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x13, 0x64,
+	0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
+	0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65,
+	0x6c, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
+	0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e,
+	0x74, 0x52, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70,
+	0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06, 0x20,
+	0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x6f, 0x6c, 0x12, 0x31, 0x0a, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
+	0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x52, 0x06, 0x6e,
+	0x6f, 0x69, 0x73, 0x65, 0x73, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61,
+	0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50,
+	0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74,
+	0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f,
+	0x78, 0x79, 0x2f, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61,
+	0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62,
+	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -507,22 +426,21 @@ func file_proxy_freedom_config_proto_rawDescGZIP() []byte {
 	return file_proxy_freedom_config_proto_rawDescData
 }
 
-var file_proxy_freedom_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
 var file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
 var file_proxy_freedom_config_proto_goTypes = []any{
-	(Config_DomainStrategy)(0),      // 0: xray.proxy.freedom.Config.DomainStrategy
-	(*DestinationOverride)(nil),     // 1: xray.proxy.freedom.DestinationOverride
-	(*Fragment)(nil),                // 2: xray.proxy.freedom.Fragment
-	(*Noise)(nil),                   // 3: xray.proxy.freedom.Noise
-	(*Config)(nil),                  // 4: xray.proxy.freedom.Config
-	(*protocol.ServerEndpoint)(nil), // 5: xray.common.protocol.ServerEndpoint
+	(*DestinationOverride)(nil),     // 0: xray.proxy.freedom.DestinationOverride
+	(*Fragment)(nil),                // 1: xray.proxy.freedom.Fragment
+	(*Noise)(nil),                   // 2: xray.proxy.freedom.Noise
+	(*Config)(nil),                  // 3: xray.proxy.freedom.Config
+	(*protocol.ServerEndpoint)(nil), // 4: xray.common.protocol.ServerEndpoint
+	(internet.DomainStrategy)(0),    // 5: xray.transport.internet.DomainStrategy
 }
 var file_proxy_freedom_config_proto_depIdxs = []int32{
-	5, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint
-	0, // 1: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.proxy.freedom.Config.DomainStrategy
-	1, // 2: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride
-	2, // 3: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment
-	3, // 4: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise
+	4, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint
+	5, // 1: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
+	0, // 2: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride
+	1, // 3: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment
+	2, // 4: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise
 	5, // [5:5] is the sub-list for method output_type
 	5, // [5:5] is the sub-list for method input_type
 	5, // [5:5] is the sub-list for extension type_name
@@ -540,14 +458,13 @@ func file_proxy_freedom_config_proto_init() {
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_proxy_freedom_config_proto_rawDesc,
-			NumEnums:      1,
+			NumEnums:      0,
 			NumMessages:   4,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
 		GoTypes:           file_proxy_freedom_config_proto_goTypes,
 		DependencyIndexes: file_proxy_freedom_config_proto_depIdxs,
-		EnumInfos:         file_proxy_freedom_config_proto_enumTypes,
 		MessageInfos:      file_proxy_freedom_config_proto_msgTypes,
 	}.Build()
 	File_proxy_freedom_config_proto = out.File

+ 2 - 14
proxy/freedom/config.proto

@@ -7,6 +7,7 @@ option java_package = "com.xray.proxy.freedom";
 option java_multiple_files = true;
 
 import "common/protocol/server_spec.proto";
+import "transport/internet/config.proto";
 
 message DestinationOverride {
   xray.common.protocol.ServerEndpoint server = 1;
@@ -32,20 +33,7 @@ message Noise {
 }
 
 message Config {
-  enum DomainStrategy {
-    AS_IS = 0;
-    USE_IP = 1;
-    USE_IP4 = 2;
-    USE_IP6 = 3;
-    USE_IP46 = 4;
-    USE_IP64 = 5;
-    FORCE_IP = 6;
-    FORCE_IP4 = 7;
-    FORCE_IP6 = 8;
-    FORCE_IP46 = 9;
-    FORCE_IP64 = 10;
-  }
-  DomainStrategy domain_strategy = 1;
+  xray.transport.internet.DomainStrategy domain_strategy = 1;
   DestinationOverride destination_override = 3;
   uint32 user_level = 4;
   Fragment fragment = 5;

+ 44 - 52
proxy/freedom/freedom.go

@@ -20,7 +20,6 @@ import (
 	"github.com/xtls/xray-core/common/task"
 	"github.com/xtls/xray-core/common/utils"
 	"github.com/xtls/xray-core/core"
-	"github.com/xtls/xray-core/features/dns"
 	"github.com/xtls/xray-core/features/policy"
 	"github.com/xtls/xray-core/features/stats"
 	"github.com/xtls/xray-core/proxy"
@@ -35,8 +34,8 @@ var useSplice bool
 func init() {
 	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
 		h := new(Handler)
-		if err := core.RequireFeatures(ctx, func(pm policy.Manager, d dns.Client) error {
-			return h.Init(config.(*Config), pm, d)
+		if err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
+			return h.Init(config.(*Config), pm)
 		}); err != nil {
 			return nil, err
 		}
@@ -53,16 +52,13 @@ func init() {
 // Handler handles Freedom connections.
 type Handler struct {
 	policyManager policy.Manager
-	dns           dns.Client
 	config        *Config
 }
 
 // Init initializes the Handler with necessary parameters.
-func (h *Handler) Init(config *Config, pm policy.Manager, d dns.Client) error {
+func (h *Handler) Init(config *Config, pm policy.Manager) error {
 	h.config = config
 	h.policyManager = pm
-	h.dns = d
-
 	return nil
 }
 
@@ -71,28 +67,6 @@ func (h *Handler) policy() policy.Session {
 	return p
 }
 
-func (h *Handler) resolveIP(ctx context.Context, domain string, localAddr net.Address) net.Address {
-	ips, _, err := h.dns.LookupIP(domain, dns.IPOption{
-		IPv4Enable: (localAddr == nil || localAddr.Family().IsIPv4()) && h.config.preferIP4(),
-		IPv6Enable: (localAddr == nil || localAddr.Family().IsIPv6()) && h.config.preferIP6(),
-	})
-	{ // Resolve fallback
-		if (len(ips) == 0 || err != nil) && h.config.hasFallback() && localAddr == nil {
-			ips, _, err = h.dns.LookupIP(domain, dns.IPOption{
-				IPv4Enable: h.config.fallbackIP4(),
-				IPv6Enable: h.config.fallbackIP6(),
-			})
-		}
-	}
-	if err != nil {
-		errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", domain)
-	}
-	if len(ips) == 0 {
-		return nil
-	}
-	return net.IPAddress(ips[dice.Roll(len(ips))])
-}
-
 func isValidAddress(addr *net.IPOrDomain) bool {
 	if addr == nil {
 		return false
@@ -114,6 +88,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
 	inbound := session.InboundFromContext(ctx)
 
 	destination := ob.Target
+	origTargetAddr := ob.OriginalTarget.Address
+	if origTargetAddr == nil {
+		origTargetAddr = ob.Target.Address
+	}
+	dialer.SetOutboundGateway(ctx, ob)
+	outGateway := ob.Gateway
 	UDPOverride := net.UDPDestination(nil, 0)
 	if h.config.DestinationOverride != nil {
 		server := h.config.DestinationOverride.Server
@@ -133,17 +113,24 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
 	var conn stat.Connection
 	err := retry.ExponentialBackoff(5, 100).On(func() error {
 		dialDest := destination
-		if h.config.hasStrategy() && dialDest.Address.Family().IsDomain() {
-			ip := h.resolveIP(ctx, dialDest.Address.Domain(), dialer.Address())
-			if ip != nil {
+		if h.config.DomainStrategy.HasStrategy() && dialDest.Address.Family().IsDomain() {
+			strategy := h.config.DomainStrategy
+			if destination.Network == net.Network_UDP && origTargetAddr != nil && outGateway == nil {
+				strategy = strategy.GetDynamicStrategy(origTargetAddr.Family())
+			}
+			ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
+			if err != nil {
+				errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
+				if h.config.DomainStrategy.ForceIP() {
+					return err
+				}
+			} else {
 				dialDest = net.Destination{
 					Network: dialDest.Network,
-					Address: ip,
+					Address: net.IPAddress(ips[dice.Roll(len(ips))]),
 					Port:    dialDest.Port,
 				}
 				errors.LogInfo(ctx, "dialing to ", dialDest)
-			} else if h.config.forceIP() {
-				return dns.ErrEmptyResponse
 			}
 		}
 
@@ -203,7 +190,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
 				writer = buf.NewWriter(conn)
 			}
 		} else {
-			writer = NewPacketWriter(conn, h, ctx, UDPOverride, destination)
+			writer = NewPacketWriter(conn, h, UDPOverride, destination)
 			if h.config.Noises != nil {
 				errors.LogDebug(ctx, "NOISE", h.config.Noises)
 				writer = &NoisePacketWriter{
@@ -339,7 +326,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
 }
 
 // DialDest means the dial target used in the dialer when creating conn
-func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride net.Destination, DialDest net.Destination) buf.Writer {
+func NewPacketWriter(conn net.Conn, h *Handler, UDPOverride net.Destination, DialDest net.Destination) buf.Writer {
 	iConn := conn
 	statConn, ok := iConn.(*stat.CounterConnection)
 	if ok {
@@ -360,9 +347,9 @@ func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride
 			PacketConnWrapper: c,
 			Counter:           counter,
 			Handler:           h,
-			Context:           ctx,
 			UDPOverride:       UDPOverride,
-			resolvedUDPAddr:   resolvedUDPAddr,
+			ResolvedUDPAddr:   resolvedUDPAddr,
+			LocalAddr:         net.DestinationFromAddr(conn.LocalAddr()).Address,
 		}
 
 	}
@@ -373,14 +360,14 @@ type PacketWriter struct {
 	*internet.PacketConnWrapper
 	stats.Counter
 	*Handler
-	context.Context
 	UDPOverride net.Destination
 
 	// Dest of udp packets might be a domain, we will resolve them to IP
 	// But resolver will return a random one if the domain has many IPs
 	// Resulting in these packets being sent to many different IPs randomly
 	// So, cache and keep the resolve result
-	resolvedUDPAddr *utils.TypedSyncMap[string, net.Address]
+	ResolvedUDPAddr *utils.TypedSyncMap[string, net.Address]
+	LocalAddr       net.Address
 }
 
 func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
@@ -400,20 +387,22 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
 				b.UDP.Port = w.UDPOverride.Port
 			}
 			if b.UDP.Address.Family().IsDomain() {
-				if ip, ok := w.resolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
+				if ip, ok := w.ResolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
 					b.UDP.Address = ip
 				} else {
 					ShouldUseSystemResolver := true
-					if w.Handler.config.hasStrategy() {
-						ip = w.Handler.resolveIP(w.Context, b.UDP.Address.Domain(), nil)
-						if ip != nil {
+					if w.Handler.config.DomainStrategy.HasStrategy() {
+						ips, err := internet.LookupForIP(b.UDP.Address.Domain(), w.Handler.config.DomainStrategy, w.LocalAddr)
+						if err != nil {
+							// drop packet if resolve failed when forceIP
+							if w.Handler.config.DomainStrategy.ForceIP() {
+								b.Release()
+								continue
+							}
+						} else {
+							ip = net.IPAddress(ips[dice.Roll(len(ips))])
 							ShouldUseSystemResolver = false
 						}
-						// drop packet if resolve failed when forceIP
-						if ip == nil && w.Handler.config.forceIP() {
-							b.Release()
-							continue
-						}
 					}
 					if ShouldUseSystemResolver {
 						udpAddr, err := net.ResolveUDPAddr("udp", b.UDP.NetAddr())
@@ -425,7 +414,7 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
 						}
 					}
 					if ip != nil {
-						b.UDP.Address, _ = w.resolvedUDPAddr.LoadOrStore(b.UDP.Address.Domain(), ip)
+						b.UDP.Address, _ = w.ResolvedUDPAddr.LoadOrStore(b.UDP.Address.Domain(), ip)
 					}
 				}
 			}
@@ -496,7 +485,10 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
 			if err != nil {
 				return err
 			}
-			w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)})
+			err = w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)})
+			if err != nil {
+				return err
+			}
 
 			if n.DelayMin != 0 || n.DelayMax != 0 {
 				time.Sleep(time.Duration(crypto.RandBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond)

+ 2 - 1
testing/scenarios/dns_test.go

@@ -16,6 +16,7 @@ import (
 	"github.com/xtls/xray-core/proxy/freedom"
 	"github.com/xtls/xray-core/proxy/socks"
 	"github.com/xtls/xray-core/testing/servers/tcp"
+	"github.com/xtls/xray-core/transport/internet"
 	xproxy "golang.org/x/net/proxy"
 )
 
@@ -83,7 +84,7 @@ func TestResolveIP(t *testing.T) {
 			{
 				Tag: "direct",
 				ProxySettings: serial.ToTypedMessage(&freedom.Config{
-					DomainStrategy: freedom.Config_USE_IP,
+					DomainStrategy: internet.DomainStrategy_USE_IP,
 				}),
 			},
 		},

+ 23 - 0
transport/internet/config.go

@@ -2,6 +2,7 @@ package internet
 
 import (
 	"github.com/xtls/xray-core/common/errors"
+	"github.com/xtls/xray-core/common/net"
 	"github.com/xtls/xray-core/common/serial"
 )
 
@@ -127,3 +128,25 @@ func (s DomainStrategy) FallbackIP4() bool {
 func (s DomainStrategy) FallbackIP6() bool {
 	return strategy[s][2] == 6
 }
+
+func (s DomainStrategy) GetDynamicStrategy(addrFamily net.AddressFamily) DomainStrategy {
+	if  addrFamily.IsDomain(){
+		return s
+	}
+	switch s {
+	case DomainStrategy_USE_IP:
+		if addrFamily.IsIPv4() {
+			return DomainStrategy_USE_IP46
+		} else if addrFamily.IsIPv6() {
+			return DomainStrategy_USE_IP64
+		}
+	case DomainStrategy_FORCE_IP:
+		if addrFamily.IsIPv4() {
+			return DomainStrategy_FORCE_IP46
+		} else if addrFamily.IsIPv6() {
+			return DomainStrategy_FORCE_IP64
+		}
+	default:
+	}
+	return s
+}

+ 21 - 15
transport/internet/dialer.go

@@ -24,11 +24,11 @@ type Dialer interface {
 	// Dial dials a system connection to the given destination.
 	Dial(ctx context.Context, destination net.Destination) (stat.Connection, error)
 
-	// Address returns the address used by this Dialer. Maybe nil if not known.
-	Address() net.Address
-
 	// DestIpAddress returns the ip of proxy server. It is useful in case of Android client, which prepare an IP before proxy connection is established
 	DestIpAddress() net.IP
+
+	// SetOutboundGateway set outbound gateway
+	SetOutboundGateway(ctx context.Context, ob *session.Outbound)
 }
 
 // dialFunc is an interface to dial network connection to a specific destination.
@@ -91,8 +91,8 @@ func LookupForIP(domain string, strategy DomainStrategy, localAddr net.Address)
 	}
 
 	ips, _, err := dnsClient.LookupIP(domain, dns.IPOption{
-		IPv4Enable: (localAddr == nil || localAddr.Family().IsIPv4()) && strategy.PreferIP4(),
-		IPv6Enable: (localAddr == nil || localAddr.Family().IsIPv6()) && strategy.PreferIP6(),
+		IPv4Enable: (localAddr == nil && strategy.PreferIP4()) || (localAddr != nil && localAddr.Family().IsIPv4() && (strategy.PreferIP4() || strategy.FallbackIP4())),
+		IPv6Enable: (localAddr == nil && strategy.PreferIP6()) || (localAddr != nil && localAddr.Family().IsIPv6() && (strategy.PreferIP6() || strategy.FallbackIP6())),
 	})
 	{ // Resolve fallback
 		if (len(ips) == 0 || err != nil) && strategy.HasFallback() && localAddr == nil {
@@ -109,13 +109,6 @@ func LookupForIP(domain string, strategy DomainStrategy, localAddr net.Address)
 	return ips, err
 }
 
-func canLookupIP(dst net.Destination, sockopt *SocketConfig) bool {
-	if dst.Address.Family().IsIP() {
-		return false
-	}
-	return sockopt.DomainStrategy.HasStrategy()
-}
-
 func redirect(ctx context.Context, dst net.Destination, obt string, h outbound.Handler) net.Conn {
 	errors.LogInfo(ctx, "redirecting request "+dst.String()+" to "+obt)
 	outbounds := session.OutboundsFromContext(ctx)
@@ -235,9 +228,18 @@ func checkAddressPortStrategy(ctx context.Context, dest net.Destination, sockopt
 func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {
 	var src net.Address
 	outbounds := session.OutboundsFromContext(ctx)
+	var outboundName string
+	var origTargetAddr net.Address
 	if len(outbounds) > 0 {
 		ob := outbounds[len(outbounds)-1]
-		src = ob.Gateway
+		if sockopt == nil || len(sockopt.DialerProxy) == 0 {
+			src = ob.Gateway
+		}
+		outboundName = ob.Name
+		origTargetAddr = ob.OriginalTarget.Address
+		if origTargetAddr == nil {
+			origTargetAddr = ob.Target.Address
+		}
 	}
 	if sockopt == nil {
 		return effectiveSystemDialer.Dial(ctx, src, dest, sockopt)
@@ -248,8 +250,12 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig
 		dest = *newDest
 	}
 
-	if canLookupIP(dest, sockopt) {
-		ips, err := LookupForIP(dest.Address.String(), sockopt.DomainStrategy, src)
+	if sockopt.DomainStrategy.HasStrategy() && dest.Address.Family().IsDomain() {
+		finalStrategy := sockopt.DomainStrategy
+		if outboundName == "freedom" && dest.Network == net.Network_UDP && origTargetAddr != nil && src == nil {
+			finalStrategy = finalStrategy.GetDynamicStrategy(origTargetAddr.Family())
+		}
+		ips, err := LookupForIP(dest.Address.Domain(), finalStrategy, src)
 		if err != nil {
 			errors.LogErrorInner(ctx, err, "failed to resolve ip")
 			if sockopt.DomainStrategy.ForceIP() {