ソースを参照

Tunnel inbound: Add `portMap` config (local listening port -> remote specified address/port)

Completes https://github.com/XTLS/Xray-core/pull/4968
RPRX 3 ヶ月 前
コミット
146b14ab55
4 ファイル変更74 行追加35 行削除
  1. 14 5
      infra/conf/dokodemo.go
  2. 47 29
      proxy/dokodemo/config.pb.go
  3. 2 0
      proxy/dokodemo/config.proto
  4. 11 1
      proxy/dokodemo/dokodemo.go

+ 14 - 5
infra/conf/dokodemo.go

@@ -1,16 +1,19 @@
 package conf
 
 import (
+	"github.com/xtls/xray-core/common/errors"
+	"github.com/xtls/xray-core/common/net"
 	"github.com/xtls/xray-core/proxy/dokodemo"
 	"google.golang.org/protobuf/proto"
 )
 
 type DokodemoConfig struct {
-	Address        *Address     `json:"address"`
-	Port           uint16       `json:"port"`
-	Network        *NetworkList `json:"network"`
-	FollowRedirect bool         `json:"followRedirect"`
-	UserLevel      uint32       `json:"userLevel"`
+	Address        *Address          `json:"address"`
+	Port           uint16            `json:"port"`
+	PortMap        map[string]string `json:"portMap"`
+	Network        *NetworkList      `json:"network"`
+	FollowRedirect bool              `json:"followRedirect"`
+	UserLevel      uint32            `json:"userLevel"`
 }
 
 func (v *DokodemoConfig) Build() (proto.Message, error) {
@@ -19,6 +22,12 @@ func (v *DokodemoConfig) Build() (proto.Message, error) {
 		config.Address = v.Address.Build()
 	}
 	config.Port = uint32(v.Port)
+	config.PortMap = v.PortMap
+	for _, v := range config.PortMap {
+		if _, _, err := net.SplitHostPort(v); err != nil {
+			return nil, errors.New("invalid portMap: ", v).Base(err)
+		}
+	}
 	config.Networks = v.Network.Build()
 	config.FollowRedirect = v.FollowRedirect
 	config.UserLevel = v.UserLevel

+ 47 - 29
proxy/dokodemo/config.pb.go

@@ -26,8 +26,9 @@ type Config struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
-	Port    uint32          `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
+	Address *net.IPOrDomain   `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
+	Port    uint32            `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
+	PortMap map[string]string `protobuf:"bytes,3,rep,name=port_map,json=portMap,proto3" json:"port_map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 	// List of networks that the Dokodemo accepts.
 	Networks       []net.Network `protobuf:"varint,7,rep,packed,name=networks,proto3,enum=xray.common.net.Network" json:"networks,omitempty"`
 	FollowRedirect bool          `protobuf:"varint,5,opt,name=follow_redirect,json=followRedirect,proto3" json:"follow_redirect,omitempty"`
@@ -78,6 +79,13 @@ func (x *Config) GetPort() uint32 {
 	return 0
 }
 
+func (x *Config) GetPortMap() map[string]string {
+	if x != nil {
+		return x.PortMap
+	}
+	return nil
+}
+
 func (x *Config) GetNetworks() []net.Network {
 	if x != nil {
 		return x.Networks
@@ -108,26 +116,34 @@ var file_proxy_dokodemo_config_proto_rawDesc = []byte{
 	0x6d, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61,
 	0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f,
 	0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
-	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd1, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd2, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
 	0x67, 0x12, 0x35, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01,
 	0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
 	0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52,
 	0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x34, 0x0a, 0x08,
-	0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x18,
-	0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
-	0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
-	0x6b, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x65, 0x64,
-	0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x66, 0x6f, 0x6c,
-	0x6c, 0x6f, 0x77, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75,
-	0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52,
-	0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x5b, 0x0a, 0x17, 0x63, 0x6f,
-	0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6f, 0x6b,
-	0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x50, 0x01, 0x5a, 0x28, 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, 0x64, 0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d,
-	0x6f, 0xaa, 0x02, 0x13, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x44,
-	0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x43, 0x0a, 0x08,
+	0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28,
+	0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6f, 0x6b, 0x6f,
+	0x64, 0x65, 0x6d, 0x6f, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x72, 0x74,
+	0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x61,
+	0x70, 0x12, 0x34, 0x0a, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x07, 0x20,
+	0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
+	0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e,
+	0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x6f, 0x6c, 0x6c, 0x6f,
+	0x77, 0x5f, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08,
+	0x52, 0x0e, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
+	0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x1a,
+	0x3a, 0x0a, 0x0c, 0x50, 0x6f, 0x72, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+	0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+	0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x5b, 0x0a, 0x17, 0x63,
+	0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6f,
+	0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x50, 0x01, 0x5a, 0x28, 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, 0x64, 0x6f, 0x6b, 0x6f, 0x64, 0x65,
+	0x6d, 0x6f, 0xaa, 0x02, 0x13, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e,
+	0x44, 0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -142,20 +158,22 @@ func file_proxy_dokodemo_config_proto_rawDescGZIP() []byte {
 	return file_proxy_dokodemo_config_proto_rawDescData
 }
 
-var file_proxy_dokodemo_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_proxy_dokodemo_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
 var file_proxy_dokodemo_config_proto_goTypes = []any{
 	(*Config)(nil),         // 0: xray.proxy.dokodemo.Config
-	(*net.IPOrDomain)(nil), // 1: xray.common.net.IPOrDomain
-	(net.Network)(0),       // 2: xray.common.net.Network
+	nil,                    // 1: xray.proxy.dokodemo.Config.PortMapEntry
+	(*net.IPOrDomain)(nil), // 2: xray.common.net.IPOrDomain
+	(net.Network)(0),       // 3: xray.common.net.Network
 }
 var file_proxy_dokodemo_config_proto_depIdxs = []int32{
-	1, // 0: xray.proxy.dokodemo.Config.address:type_name -> xray.common.net.IPOrDomain
-	2, // 1: xray.proxy.dokodemo.Config.networks:type_name -> xray.common.net.Network
-	2, // [2:2] is the sub-list for method output_type
-	2, // [2:2] is the sub-list for method input_type
-	2, // [2:2] is the sub-list for extension type_name
-	2, // [2:2] is the sub-list for extension extendee
-	0, // [0:2] is the sub-list for field type_name
+	2, // 0: xray.proxy.dokodemo.Config.address:type_name -> xray.common.net.IPOrDomain
+	1, // 1: xray.proxy.dokodemo.Config.port_map:type_name -> xray.proxy.dokodemo.Config.PortMapEntry
+	3, // 2: xray.proxy.dokodemo.Config.networks:type_name -> xray.common.net.Network
+	3, // [3:3] is the sub-list for method output_type
+	3, // [3:3] is the sub-list for method input_type
+	3, // [3:3] is the sub-list for extension type_name
+	3, // [3:3] is the sub-list for extension extendee
+	0, // [0:3] is the sub-list for field type_name
 }
 
 func init() { file_proxy_dokodemo_config_proto_init() }
@@ -169,7 +187,7 @@ func file_proxy_dokodemo_config_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_proxy_dokodemo_config_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   1,
+			NumMessages:   2,
 			NumExtensions: 0,
 			NumServices:   0,
 		},

+ 2 - 0
proxy/dokodemo/config.proto

@@ -13,6 +13,8 @@ message Config {
   xray.common.net.IPOrDomain address = 1;
   uint32 port = 2;
 
+  map<string, string> port_map = 3;
+
   // List of networks that the Dokodemo accepts.
   repeated xray.common.net.Network networks = 7;
 

+ 11 - 1
proxy/dokodemo/dokodemo.go

@@ -38,6 +38,7 @@ type DokodemoDoor struct {
 	config        *Config
 	address       net.Address
 	port          net.Port
+	portMap       map[string]string
 	sockopt       *session.Sockopt
 }
 
@@ -49,6 +50,7 @@ func (d *DokodemoDoor) Init(config *Config, pm policy.Manager, sockopt *session.
 	d.config = config
 	d.address = config.GetPredefinedAddress()
 	d.port = net.Port(config.Port)
+	d.portMap = config.PortMap
 	d.policyManager = pm
 	d.sockopt = sockopt
 
@@ -91,7 +93,15 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
 		if dest.Port == 0 {
 			dest.Port = net.Port(common.Must2(strconv.Atoi(port)).(int))
 		}
-
+		if d.portMap != nil && d.portMap[port] != "" {
+			h, p, _ := net.SplitHostPort(d.portMap[port])
+			if len(h) > 0 {
+				dest.Address = net.ParseAddress(h)
+			}
+			if len(p) > 0 {
+				dest.Port = net.Port(common.Must2(strconv.Atoi(p)).(int))
+			}
+		}
 	}
 
 	destinationOverridden := false