From b9cb93d3c23d3a66716123628d37943ffc41d2eb Mon Sep 17 00:00:00 2001 From: j3l11234 <297259024@qq.com> Date: Sun, 2 Mar 2025 21:07:55 +0800 Subject: [PATCH] Sockopt: Add `addressPortStrategy` (query SRV or TXT) (#4416) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 风扇滑翔翼 --- infra/conf/transport_internet.go | 22 ++++ transport/internet/config.pb.go | 215 ++++++++++++++++++++++--------- transport/internet/config.proto | 12 ++ transport/internet/dialer.go | 95 ++++++++++++++ 4 files changed, 280 insertions(+), 64 deletions(-) diff --git a/infra/conf/transport_internet.go b/infra/conf/transport_internet.go index 7b993a36..0de5bfcc 100644 --- a/infra/conf/transport_internet.go +++ b/infra/conf/transport_internet.go @@ -711,6 +711,7 @@ type SocketConfig struct { Interface string `json:"interface"` TcpMptcp bool `json:"tcpMptcp"` CustomSockopt []*CustomSockoptConfig `json:"customSockopt"` + AddressPortStrategy string `json:"addressPortStrategy"` } // Build implements Buildable. @@ -780,6 +781,26 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) { customSockopts = append(customSockopts, customSockopt) } + addressPortStrategy := internet.AddressPortStrategy_None + switch strings.ToLower(c.AddressPortStrategy) { + case "none", "": + addressPortStrategy = internet.AddressPortStrategy_None + case "srvportonly": + addressPortStrategy = internet.AddressPortStrategy_SrvPortOnly + case "srvaddressonly": + addressPortStrategy = internet.AddressPortStrategy_SrvAddressOnly + case "srvportandaddress": + addressPortStrategy = internet.AddressPortStrategy_SrvPortAndAddress + case "txtportonly": + addressPortStrategy = internet.AddressPortStrategy_TxtPortOnly + case "txtaddressonly": + addressPortStrategy = internet.AddressPortStrategy_TxtAddressOnly + case "txtportandaddress": + addressPortStrategy = internet.AddressPortStrategy_TxtPortAndAddress + default: + return nil, errors.New("unsupported address and port strategy: ", c.AddressPortStrategy) + } + return &internet.SocketConfig{ Mark: c.Mark, Tfo: tfo, @@ -798,6 +819,7 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) { Interface: c.Interface, TcpMptcp: c.TcpMptcp, CustomSockopt: customSockopts, + AddressPortStrategy: addressPortStrategy, }, nil } diff --git a/transport/internet/config.pb.go b/transport/internet/config.pb.go index d74fa665..ae1b38f3 100644 --- a/transport/internet/config.pb.go +++ b/transport/internet/config.pb.go @@ -95,6 +95,67 @@ func (DomainStrategy) EnumDescriptor() ([]byte, []int) { return file_transport_internet_config_proto_rawDescGZIP(), []int{0} } +type AddressPortStrategy int32 + +const ( + AddressPortStrategy_None AddressPortStrategy = 0 + AddressPortStrategy_SrvPortOnly AddressPortStrategy = 1 + AddressPortStrategy_SrvAddressOnly AddressPortStrategy = 2 + AddressPortStrategy_SrvPortAndAddress AddressPortStrategy = 3 + AddressPortStrategy_TxtPortOnly AddressPortStrategy = 4 + AddressPortStrategy_TxtAddressOnly AddressPortStrategy = 5 + AddressPortStrategy_TxtPortAndAddress AddressPortStrategy = 6 +) + +// Enum value maps for AddressPortStrategy. +var ( + AddressPortStrategy_name = map[int32]string{ + 0: "None", + 1: "SrvPortOnly", + 2: "SrvAddressOnly", + 3: "SrvPortAndAddress", + 4: "TxtPortOnly", + 5: "TxtAddressOnly", + 6: "TxtPortAndAddress", + } + AddressPortStrategy_value = map[string]int32{ + "None": 0, + "SrvPortOnly": 1, + "SrvAddressOnly": 2, + "SrvPortAndAddress": 3, + "TxtPortOnly": 4, + "TxtAddressOnly": 5, + "TxtPortAndAddress": 6, + } +) + +func (x AddressPortStrategy) Enum() *AddressPortStrategy { + p := new(AddressPortStrategy) + *p = x + return p +} + +func (x AddressPortStrategy) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AddressPortStrategy) Descriptor() protoreflect.EnumDescriptor { + return file_transport_internet_config_proto_enumTypes[1].Descriptor() +} + +func (AddressPortStrategy) Type() protoreflect.EnumType { + return &file_transport_internet_config_proto_enumTypes[1] +} + +func (x AddressPortStrategy) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AddressPortStrategy.Descriptor instead. +func (AddressPortStrategy) EnumDescriptor() ([]byte, []int) { + return file_transport_internet_config_proto_rawDescGZIP(), []int{1} +} + type SocketConfig_TProxyMode int32 const ( @@ -131,11 +192,11 @@ func (x SocketConfig_TProxyMode) String() string { } func (SocketConfig_TProxyMode) Descriptor() protoreflect.EnumDescriptor { - return file_transport_internet_config_proto_enumTypes[1].Descriptor() + return file_transport_internet_config_proto_enumTypes[2].Descriptor() } func (SocketConfig_TProxyMode) Type() protoreflect.EnumType { - return &file_transport_internet_config_proto_enumTypes[1] + return &file_transport_internet_config_proto_enumTypes[2] } func (x SocketConfig_TProxyMode) Number() protoreflect.EnumNumber { @@ -434,23 +495,24 @@ type SocketConfig struct { Tproxy SocketConfig_TProxyMode `protobuf:"varint,3,opt,name=tproxy,proto3,enum=xray.transport.internet.SocketConfig_TProxyMode" json:"tproxy,omitempty"` // ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket // option. This option is for UDP only. - ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"` - BindAddress []byte `protobuf:"bytes,5,opt,name=bind_address,json=bindAddress,proto3" json:"bind_address,omitempty"` - BindPort uint32 `protobuf:"varint,6,opt,name=bind_port,json=bindPort,proto3" json:"bind_port,omitempty"` - AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"` - DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"` - DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"` - TcpKeepAliveInterval int32 `protobuf:"varint,10,opt,name=tcp_keep_alive_interval,json=tcpKeepAliveInterval,proto3" json:"tcp_keep_alive_interval,omitempty"` - TcpKeepAliveIdle int32 `protobuf:"varint,11,opt,name=tcp_keep_alive_idle,json=tcpKeepAliveIdle,proto3" json:"tcp_keep_alive_idle,omitempty"` - TcpCongestion string `protobuf:"bytes,12,opt,name=tcp_congestion,json=tcpCongestion,proto3" json:"tcp_congestion,omitempty"` - Interface string `protobuf:"bytes,13,opt,name=interface,proto3" json:"interface,omitempty"` - V6Only bool `protobuf:"varint,14,opt,name=v6only,proto3" json:"v6only,omitempty"` - TcpWindowClamp int32 `protobuf:"varint,15,opt,name=tcp_window_clamp,json=tcpWindowClamp,proto3" json:"tcp_window_clamp,omitempty"` - TcpUserTimeout int32 `protobuf:"varint,16,opt,name=tcp_user_timeout,json=tcpUserTimeout,proto3" json:"tcp_user_timeout,omitempty"` - TcpMaxSeg int32 `protobuf:"varint,17,opt,name=tcp_max_seg,json=tcpMaxSeg,proto3" json:"tcp_max_seg,omitempty"` - Penetrate bool `protobuf:"varint,18,opt,name=penetrate,proto3" json:"penetrate,omitempty"` - TcpMptcp bool `protobuf:"varint,19,opt,name=tcp_mptcp,json=tcpMptcp,proto3" json:"tcp_mptcp,omitempty"` - CustomSockopt []*CustomSockopt `protobuf:"bytes,20,rep,name=customSockopt,proto3" json:"customSockopt,omitempty"` + ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"` + BindAddress []byte `protobuf:"bytes,5,opt,name=bind_address,json=bindAddress,proto3" json:"bind_address,omitempty"` + BindPort uint32 `protobuf:"varint,6,opt,name=bind_port,json=bindPort,proto3" json:"bind_port,omitempty"` + AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"` + DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"` + DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"` + TcpKeepAliveInterval int32 `protobuf:"varint,10,opt,name=tcp_keep_alive_interval,json=tcpKeepAliveInterval,proto3" json:"tcp_keep_alive_interval,omitempty"` + TcpKeepAliveIdle int32 `protobuf:"varint,11,opt,name=tcp_keep_alive_idle,json=tcpKeepAliveIdle,proto3" json:"tcp_keep_alive_idle,omitempty"` + TcpCongestion string `protobuf:"bytes,12,opt,name=tcp_congestion,json=tcpCongestion,proto3" json:"tcp_congestion,omitempty"` + Interface string `protobuf:"bytes,13,opt,name=interface,proto3" json:"interface,omitempty"` + V6Only bool `protobuf:"varint,14,opt,name=v6only,proto3" json:"v6only,omitempty"` + TcpWindowClamp int32 `protobuf:"varint,15,opt,name=tcp_window_clamp,json=tcpWindowClamp,proto3" json:"tcp_window_clamp,omitempty"` + TcpUserTimeout int32 `protobuf:"varint,16,opt,name=tcp_user_timeout,json=tcpUserTimeout,proto3" json:"tcp_user_timeout,omitempty"` + TcpMaxSeg int32 `protobuf:"varint,17,opt,name=tcp_max_seg,json=tcpMaxSeg,proto3" json:"tcp_max_seg,omitempty"` + Penetrate bool `protobuf:"varint,18,opt,name=penetrate,proto3" json:"penetrate,omitempty"` + TcpMptcp bool `protobuf:"varint,19,opt,name=tcp_mptcp,json=tcpMptcp,proto3" json:"tcp_mptcp,omitempty"` + CustomSockopt []*CustomSockopt `protobuf:"bytes,20,rep,name=customSockopt,proto3" json:"customSockopt,omitempty"` + AddressPortStrategy AddressPortStrategy `protobuf:"varint,21,opt,name=address_port_strategy,json=addressPortStrategy,proto3,enum=xray.transport.internet.AddressPortStrategy" json:"address_port_strategy,omitempty"` } func (x *SocketConfig) Reset() { @@ -623,6 +685,13 @@ func (x *SocketConfig) GetCustomSockopt() []*CustomSockopt { return nil } +func (x *SocketConfig) GetAddressPortStrategy() AddressPortStrategy { + if x != nil { + return x.AddressPortStrategy + } + return AddressPortStrategy_None +} + var File_transport_internet_config_proto protoreflect.FileDescriptor var file_transport_internet_config_proto_rawDesc = []byte{ @@ -678,7 +747,7 @@ var file_transport_internet_config_proto_rawDesc = []byte{ 0x28, 0x09, 0x52, 0x03, 0x6f, 0x70, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x22, 0x9b, 0x07, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, + 0x65, 0x22, 0xfd, 0x07, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x74, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x06, 0x74, 0x70, 0x72, 0x6f, @@ -732,28 +801,44 @@ var file_transport_internet_config_proto_rawDesc = []byte{ 0x74, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 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, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x6f, 0x63, 0x6b, 0x6f, 0x70, 0x74, 0x52, - 0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x6f, 0x63, 0x6b, 0x6f, 0x70, 0x74, 0x22, 0x2f, - 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03, - 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10, - 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a, - 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, 0x67, 0x0a, 0x1b, 0x63, - 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 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, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, - 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, - 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x6f, 0x63, 0x6b, 0x6f, 0x70, 0x74, 0x12, 0x60, + 0x0a, 0x15, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, + 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 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, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, + 0x6f, 0x72, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x13, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, + 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, + 0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, + 0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, + 0x02, 0x2a, 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, 0x2a, 0x97, 0x01, + 0x0a, 0x13, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x72, + 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12, + 0x0f, 0x0a, 0x0b, 0x53, 0x72, 0x76, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x01, + 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x72, 0x76, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x6e, + 0x6c, 0x79, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x72, 0x76, 0x50, 0x6f, 0x72, 0x74, 0x41, + 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x54, + 0x78, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, + 0x54, 0x78, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x05, + 0x12, 0x15, 0x0a, 0x11, 0x54, 0x78, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x41, 0x6e, 0x64, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x06, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x78, + 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 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, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -768,33 +853,35 @@ func file_transport_internet_config_proto_rawDescGZIP() []byte { return file_transport_internet_config_proto_rawDescData } -var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_transport_internet_config_proto_goTypes = []any{ (DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy - (SocketConfig_TProxyMode)(0), // 1: xray.transport.internet.SocketConfig.TProxyMode - (*TransportConfig)(nil), // 2: xray.transport.internet.TransportConfig - (*StreamConfig)(nil), // 3: xray.transport.internet.StreamConfig - (*ProxyConfig)(nil), // 4: xray.transport.internet.ProxyConfig - (*CustomSockopt)(nil), // 5: xray.transport.internet.CustomSockopt - (*SocketConfig)(nil), // 6: xray.transport.internet.SocketConfig - (*serial.TypedMessage)(nil), // 7: xray.common.serial.TypedMessage - (*net.IPOrDomain)(nil), // 8: xray.common.net.IPOrDomain + (AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy + (SocketConfig_TProxyMode)(0), // 2: xray.transport.internet.SocketConfig.TProxyMode + (*TransportConfig)(nil), // 3: xray.transport.internet.TransportConfig + (*StreamConfig)(nil), // 4: xray.transport.internet.StreamConfig + (*ProxyConfig)(nil), // 5: xray.transport.internet.ProxyConfig + (*CustomSockopt)(nil), // 6: xray.transport.internet.CustomSockopt + (*SocketConfig)(nil), // 7: xray.transport.internet.SocketConfig + (*serial.TypedMessage)(nil), // 8: xray.common.serial.TypedMessage + (*net.IPOrDomain)(nil), // 9: xray.common.net.IPOrDomain } var file_transport_internet_config_proto_depIdxs = []int32{ - 7, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage - 8, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain - 2, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig - 7, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage - 6, // 4: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig - 1, // 5: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode + 8, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage + 9, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain + 3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig + 8, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage + 7, // 4: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig + 2, // 5: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode 0, // 6: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy - 5, // 7: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt - 8, // [8:8] is the sub-list for method output_type - 8, // [8:8] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name + 6, // 7: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt + 1, // 8: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy + 9, // [9:9] is the sub-list for method output_type + 9, // [9:9] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_transport_internet_config_proto_init() } @@ -807,7 +894,7 @@ func file_transport_internet_config_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_transport_internet_config_proto_rawDesc, - NumEnums: 2, + NumEnums: 3, NumMessages: 5, NumExtensions: 0, NumServices: 0, diff --git a/transport/internet/config.proto b/transport/internet/config.proto index 9293179e..d51998b2 100644 --- a/transport/internet/config.proto +++ b/transport/internet/config.proto @@ -23,6 +23,16 @@ enum DomainStrategy { FORCE_IP64 = 10; } +enum AddressPortStrategy { + None = 0; + SrvPortOnly = 1; + SrvAddressOnly = 2; + SrvPortAndAddress = 3; + TxtPortOnly = 4; + TxtAddressOnly = 5; + TxtPortAndAddress = 6; +} + message TransportConfig { // Transport protocol name. string protocol_name = 3; @@ -116,4 +126,6 @@ message SocketConfig { bool tcp_mptcp = 19; repeated CustomSockopt customSockopt = 20; + + AddressPortStrategy address_port_strategy = 21; } diff --git a/transport/internet/dialer.go b/transport/internet/dialer.go index 8ab51551..3b6fbfd5 100644 --- a/transport/internet/dialer.go +++ b/transport/internet/dialer.go @@ -2,6 +2,9 @@ package internet import ( "context" + "fmt" + gonet "net" + "strings" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/dice" @@ -140,6 +143,93 @@ func redirect(ctx context.Context, dst net.Destination, obt string) net.Conn { return nil } +func checkAddressPortStrategy(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (*net.Destination, error) { + if sockopt.AddressPortStrategy == AddressPortStrategy_None { + return nil, nil + } + newDest := dest + var OverridePort, OverrideAddress bool + var OverrideBy string + switch sockopt.AddressPortStrategy { + case AddressPortStrategy_SrvPortOnly: + OverridePort = true + OverrideAddress = false + OverrideBy = "srv" + case AddressPortStrategy_SrvAddressOnly: + OverridePort = false + OverrideAddress = true + OverrideBy = "srv" + case AddressPortStrategy_SrvPortAndAddress: + OverridePort = true + OverrideAddress = true + OverrideBy = "srv" + case AddressPortStrategy_TxtPortOnly: + OverridePort = true + OverrideAddress = false + OverrideBy = "txt" + case AddressPortStrategy_TxtAddressOnly: + OverridePort = false + OverrideAddress = true + OverrideBy = "txt" + case AddressPortStrategy_TxtPortAndAddress: + OverridePort = true + OverrideAddress = true + OverrideBy = "txt" + default: + return nil, errors.New("unknown AddressPortStrategy") + } + + if !dest.Address.Family().IsDomain() { + return nil, nil + } + + if OverrideBy == "srv" { + errors.LogDebug(ctx, "query SRV record for "+dest.Address.String()) + parts := strings.SplitN(dest.Address.String(), ".", 3) + if len(parts) != 3 { + return nil, errors.New("invalid address format", dest.Address.String()) + } + _, srvRecords, err := gonet.DefaultResolver.LookupSRV(context.Background(), parts[0][1:], parts[1][1:], parts[2]) + if err != nil { + return nil, errors.New("failed to lookup SRV record").Base(err) + } + errors.LogDebug(ctx, "SRV record: "+fmt.Sprintf("addr=%s, port=%d, priority=%d, weight=%d", srvRecords[0].Target, srvRecords[0].Port, srvRecords[0].Priority, srvRecords[0].Weight)) + if OverridePort { + newDest.Port = net.Port(srvRecords[0].Port) + } + if OverrideAddress { + newDest.Address = net.ParseAddress(srvRecords[0].Target) + } + return &newDest, nil + } + if OverrideBy == "txt" { + errors.LogDebug(ctx, "query TXT record for "+dest.Address.String()) + txtRecords, err := gonet.DefaultResolver.LookupTXT(ctx, dest.Address.String()) + if err != nil { + errors.LogError(ctx, "failed to lookup SRV record: "+err.Error()) + return nil, errors.New("failed to lookup SRV record").Base(err) + } + for _, txtRecord := range txtRecords { + errors.LogDebug(ctx, "TXT record: "+txtRecord) + addr_s, port_s, _ := net.SplitHostPort(string(txtRecord)) + addr := net.ParseAddress(addr_s) + port, err := net.PortFromString(port_s) + if err != nil { + continue + } + + if OverridePort { + newDest.Port = port + } + if OverrideAddress { + newDest.Address = addr + } + return &newDest, nil + } + } + return nil, nil +} + // DialSystem calls system dialer to create a network connection. func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) { var src net.Address @@ -152,6 +242,11 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig return effectiveSystemDialer.Dial(ctx, src, dest, sockopt) } + if newDest, err := checkAddressPortStrategy(ctx, dest, sockopt); err == nil && newDest != nil { + errors.LogInfo(ctx, "replace destination with "+newDest.String()) + dest = *newDest + } + if canLookupIP(ctx, dest, sockopt) { ips, err := lookupIP(dest.Address.String(), sockopt.DomainStrategy, src) if err == nil && len(ips) > 0 {