mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-09-19 18:36:10 -04:00
Add (Experimental) Meyka Building Blocks to request Transport (#3120)
* add packetconn assembler * let kcp use environment dependency injection * Add destination override to simplified setting * add dtls dialer * add dtls listener * add dtls to default * fix bugs * add debug options to freedom outbound * fix kcp test failure for transport environment
This commit is contained in:
parent
b1079aae71
commit
7db39fb566
3
go.mod
3
go.mod
@ -9,6 +9,7 @@ require (
|
|||||||
github.com/go-chi/chi/v5 v5.0.12
|
github.com/go-chi/chi/v5 v5.0.12
|
||||||
github.com/go-chi/render v1.0.3
|
github.com/go-chi/render v1.0.3
|
||||||
github.com/go-playground/validator/v10 v10.20.0
|
github.com/go-playground/validator/v10 v10.20.0
|
||||||
|
github.com/golang-collections/go-datastructures v0.0.0-20150211160725-59788d5eb259
|
||||||
github.com/golang/mock v1.6.0
|
github.com/golang/mock v1.6.0
|
||||||
github.com/golang/protobuf v1.5.4
|
github.com/golang/protobuf v1.5.4
|
||||||
github.com/google/go-cmp v0.6.0
|
github.com/google/go-cmp v0.6.0
|
||||||
@ -19,6 +20,7 @@ require (
|
|||||||
github.com/miekg/dns v1.1.59
|
github.com/miekg/dns v1.1.59
|
||||||
github.com/mustafaturan/bus v1.0.2
|
github.com/mustafaturan/bus v1.0.2
|
||||||
github.com/pelletier/go-toml v1.9.5
|
github.com/pelletier/go-toml v1.9.5
|
||||||
|
github.com/pion/dtls/v2 v2.2.7
|
||||||
github.com/pion/transport/v2 v2.2.5
|
github.com/pion/transport/v2 v2.2.5
|
||||||
github.com/pires/go-proxyproto v0.7.0
|
github.com/pires/go-proxyproto v0.7.0
|
||||||
github.com/quic-go/quic-go v0.43.0
|
github.com/quic-go/quic-go v0.43.0
|
||||||
@ -67,7 +69,6 @@ require (
|
|||||||
github.com/mustafaturan/monoton v1.0.0 // indirect
|
github.com/mustafaturan/monoton v1.0.0 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.10.0 // indirect
|
github.com/onsi/ginkgo/v2 v2.10.0 // indirect
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
github.com/pion/dtls/v2 v2.2.7 // indirect
|
|
||||||
github.com/pion/logging v0.2.2 // indirect
|
github.com/pion/logging v0.2.2 // indirect
|
||||||
github.com/pion/randutil v0.1.0 // indirect
|
github.com/pion/randutil v0.1.0 // indirect
|
||||||
github.com/pion/sctp v1.8.7 // indirect
|
github.com/pion/sctp v1.8.7 // indirect
|
||||||
|
1
go.sum
1
go.sum
@ -92,6 +92,7 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe
|
|||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/golang-collections/go-datastructures v0.0.0-20150211160725-59788d5eb259 h1:ZHJ7+IGpuOXtVf6Zk/a3WuHQgkC+vXwaqfUBDFwahtI=
|
||||||
github.com/golang-collections/go-datastructures v0.0.0-20150211160725-59788d5eb259/go.mod h1:9Qcha0gTWLw//0VNka1Cbnjvg3pNKGFdAm7E9sBabxE=
|
github.com/golang-collections/go-datastructures v0.0.0-20150211160725-59788d5eb259/go.mod h1:9Qcha0gTWLw//0VNka1Cbnjvg3pNKGFdAm7E9sBabxE=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
@ -74,8 +74,12 @@ import (
|
|||||||
_ "github.com/v2fly/v2ray-core/v5/transport/internet/request/assembler/simple"
|
_ "github.com/v2fly/v2ray-core/v5/transport/internet/request/assembler/simple"
|
||||||
_ "github.com/v2fly/v2ray-core/v5/transport/internet/request/roundtripper/httprt"
|
_ "github.com/v2fly/v2ray-core/v5/transport/internet/request/roundtripper/httprt"
|
||||||
|
|
||||||
|
_ "github.com/v2fly/v2ray-core/v5/transport/internet/request/assembler/packetconn"
|
||||||
|
|
||||||
_ "github.com/v2fly/v2ray-core/v5/transport/internet/request/stereotype/meek"
|
_ "github.com/v2fly/v2ray-core/v5/transport/internet/request/stereotype/meek"
|
||||||
|
|
||||||
|
_ "github.com/v2fly/v2ray-core/v5/transport/internet/dtls"
|
||||||
|
|
||||||
_ "github.com/v2fly/v2ray-core/v5/transport/internet/httpupgrade"
|
_ "github.com/v2fly/v2ray-core/v5/transport/internet/httpupgrade"
|
||||||
|
|
||||||
// Transport headers
|
// Transport headers
|
||||||
|
@ -16,6 +16,55 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ProtocolReplacement int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProtocolReplacement_IDENTITY ProtocolReplacement = 0
|
||||||
|
ProtocolReplacement_FORCE_TCP ProtocolReplacement = 1
|
||||||
|
ProtocolReplacement_FORCE_UDP ProtocolReplacement = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for ProtocolReplacement.
|
||||||
|
var (
|
||||||
|
ProtocolReplacement_name = map[int32]string{
|
||||||
|
0: "IDENTITY",
|
||||||
|
1: "FORCE_TCP",
|
||||||
|
2: "FORCE_UDP",
|
||||||
|
}
|
||||||
|
ProtocolReplacement_value = map[string]int32{
|
||||||
|
"IDENTITY": 0,
|
||||||
|
"FORCE_TCP": 1,
|
||||||
|
"FORCE_UDP": 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x ProtocolReplacement) Enum() *ProtocolReplacement {
|
||||||
|
p := new(ProtocolReplacement)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x ProtocolReplacement) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ProtocolReplacement) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_proxy_freedom_config_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ProtocolReplacement) Type() protoreflect.EnumType {
|
||||||
|
return &file_proxy_freedom_config_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x ProtocolReplacement) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtocolReplacement.Descriptor instead.
|
||||||
|
func (ProtocolReplacement) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
type Config_DomainStrategy int32
|
type Config_DomainStrategy int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -52,11 +101,11 @@ func (x Config_DomainStrategy) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (Config_DomainStrategy) Descriptor() protoreflect.EnumDescriptor {
|
func (Config_DomainStrategy) Descriptor() protoreflect.EnumDescriptor {
|
||||||
return file_proxy_freedom_config_proto_enumTypes[0].Descriptor()
|
return file_proxy_freedom_config_proto_enumTypes[1].Descriptor()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Config_DomainStrategy) Type() protoreflect.EnumType {
|
func (Config_DomainStrategy) Type() protoreflect.EnumType {
|
||||||
return &file_proxy_freedom_config_proto_enumTypes[0]
|
return &file_proxy_freedom_config_proto_enumTypes[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x Config_DomainStrategy) Number() protoreflect.EnumNumber {
|
func (x Config_DomainStrategy) Number() protoreflect.EnumNumber {
|
||||||
@ -125,6 +174,7 @@ type Config struct {
|
|||||||
Timeout uint32 `protobuf:"varint,2,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
Timeout uint32 `protobuf:"varint,2,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||||
DestinationOverride *DestinationOverride `protobuf:"bytes,3,opt,name=destination_override,json=destinationOverride,proto3" json:"destination_override,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"`
|
UserLevel uint32 `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
|
||||||
|
ProtocolReplacement ProtocolReplacement `protobuf:"varint,5,opt,name=protocol_replacement,json=protocolReplacement,proto3,enum=v2ray.core.proxy.freedom.ProtocolReplacement" json:"protocol_replacement,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@ -188,10 +238,20 @@ func (x *Config) GetUserLevel() uint32 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetProtocolReplacement() ProtocolReplacement {
|
||||||
|
if x != nil {
|
||||||
|
return x.ProtocolReplacement
|
||||||
|
}
|
||||||
|
return ProtocolReplacement_IDENTITY
|
||||||
|
}
|
||||||
|
|
||||||
type SimplifiedConfig struct {
|
type SimplifiedConfig struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
DestinationOverride *DestinationOverride `protobuf:"bytes,3,opt,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
|
||||||
|
ProtocolReplacement ProtocolReplacement `protobuf:"varint,5,opt,name=protocol_replacement,json=protocolReplacement,proto3,enum=v2ray.core.proxy.freedom.ProtocolReplacement" json:"protocol_replacement,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SimplifiedConfig) Reset() {
|
func (x *SimplifiedConfig) Reset() {
|
||||||
@ -226,6 +286,20 @@ func (*SimplifiedConfig) Descriptor() ([]byte, []int) {
|
|||||||
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{2}
|
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *SimplifiedConfig) GetDestinationOverride() *DestinationOverride {
|
||||||
|
if x != nil {
|
||||||
|
return x.DestinationOverride
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SimplifiedConfig) GetProtocolReplacement() ProtocolReplacement {
|
||||||
|
if x != nil {
|
||||||
|
return x.ProtocolReplacement
|
||||||
|
}
|
||||||
|
return ProtocolReplacement_IDENTITY
|
||||||
|
}
|
||||||
|
|
||||||
var File_proxy_freedom_config_proto protoreflect.FileDescriptor
|
var File_proxy_freedom_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_proxy_freedom_config_proto_rawDesc = []byte{
|
var file_proxy_freedom_config_proto_rawDesc = []byte{
|
||||||
@ -242,7 +316,7 @@ var file_proxy_freedom_config_proto_rawDesc = []byte{
|
|||||||
0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
||||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 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,
|
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06,
|
||||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0xc4, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0xa6, 0x03, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
0x67, 0x12, 0x58, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61,
|
0x67, 0x12, 0x58, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61,
|
||||||
0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x76, 0x32, 0x72,
|
0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x76, 0x32, 0x72,
|
||||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72,
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72,
|
||||||
@ -258,21 +332,44 @@ var file_proxy_freedom_config_proto_rawDesc = []byte{
|
|||||||
0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
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,
|
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,
|
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, 0x22, 0x41, 0x0a, 0x0e, 0x44, 0x6f,
|
0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x60, 0x0a, 0x14, 0x70, 0x72,
|
||||||
0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05,
|
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65,
|
||||||
0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49,
|
0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
|
||||||
0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02,
|
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65,
|
||||||
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x22, 0x2b, 0x0a,
|
0x64, 0x6f, 0x6d, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x65, 0x70, 0x6c,
|
||||||
0x10, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
|
||||||
0x67, 0x3a, 0x17, 0x82, 0xb5, 0x18, 0x13, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,
|
0x6c, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x41, 0x0a, 0x0e,
|
||||||
0x64, 0x12, 0x07, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x42, 0x69, 0x0a, 0x1c, 0x63, 0x6f,
|
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09,
|
||||||
0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45,
|
||||||
0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69,
|
0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34,
|
||||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76,
|
0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x22,
|
||||||
0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x35, 0x2f, 0x70, 0x72, 0x6f,
|
0xef, 0x01, 0x0a, 0x10, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f,
|
||||||
0x78, 0x79, 0x2f, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x18, 0x56, 0x32, 0x52,
|
0x6e, 0x66, 0x69, 0x67, 0x12, 0x60, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
||||||
0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46, 0x72,
|
0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01,
|
||||||
0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 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, 0x60, 0x0a, 0x14, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
|
||||||
|
0x6f, 0x6c, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05,
|
||||||
|
0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
|
||||||
|
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e,
|
||||||
|
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d,
|
||||||
|
0x65, 0x6e, 0x74, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x65, 0x70,
|
||||||
|
0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x17, 0x82, 0xb5, 0x18, 0x13, 0x0a, 0x08,
|
||||||
|
0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x07, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f,
|
||||||
|
0x6d, 0x2a, 0x41, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x65, 0x70,
|
||||||
|
0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x44, 0x45, 0x4e,
|
||||||
|
0x54, 0x49, 0x54, 0x59, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f,
|
||||||
|
0x54, 0x43, 0x50, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x55,
|
||||||
|
0x44, 0x50, 0x10, 0x02, 0x42, 0x69, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61,
|
||||||
|
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65,
|
||||||
|
0x65, 0x64, 0x6f, 0x6d, 0x50, 0x01, 0x5a, 0x2c, 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, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x66, 0x72, 0x65,
|
||||||
|
0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x18, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72,
|
||||||
|
0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62,
|
||||||
|
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -287,24 +384,28 @@ func file_proxy_freedom_config_proto_rawDescGZIP() []byte {
|
|||||||
return file_proxy_freedom_config_proto_rawDescData
|
return file_proxy_freedom_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_proxy_freedom_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
var file_proxy_freedom_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||||
var file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
var file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||||
var file_proxy_freedom_config_proto_goTypes = []interface{}{
|
var file_proxy_freedom_config_proto_goTypes = []any{
|
||||||
(Config_DomainStrategy)(0), // 0: v2ray.core.proxy.freedom.Config.DomainStrategy
|
(ProtocolReplacement)(0), // 0: v2ray.core.proxy.freedom.ProtocolReplacement
|
||||||
(*DestinationOverride)(nil), // 1: v2ray.core.proxy.freedom.DestinationOverride
|
(Config_DomainStrategy)(0), // 1: v2ray.core.proxy.freedom.Config.DomainStrategy
|
||||||
(*Config)(nil), // 2: v2ray.core.proxy.freedom.Config
|
(*DestinationOverride)(nil), // 2: v2ray.core.proxy.freedom.DestinationOverride
|
||||||
(*SimplifiedConfig)(nil), // 3: v2ray.core.proxy.freedom.SimplifiedConfig
|
(*Config)(nil), // 3: v2ray.core.proxy.freedom.Config
|
||||||
(*protocol.ServerEndpoint)(nil), // 4: v2ray.core.common.protocol.ServerEndpoint
|
(*SimplifiedConfig)(nil), // 4: v2ray.core.proxy.freedom.SimplifiedConfig
|
||||||
|
(*protocol.ServerEndpoint)(nil), // 5: v2ray.core.common.protocol.ServerEndpoint
|
||||||
}
|
}
|
||||||
var file_proxy_freedom_config_proto_depIdxs = []int32{
|
var file_proxy_freedom_config_proto_depIdxs = []int32{
|
||||||
4, // 0: v2ray.core.proxy.freedom.DestinationOverride.server:type_name -> v2ray.core.common.protocol.ServerEndpoint
|
5, // 0: v2ray.core.proxy.freedom.DestinationOverride.server:type_name -> v2ray.core.common.protocol.ServerEndpoint
|
||||||
0, // 1: v2ray.core.proxy.freedom.Config.domain_strategy:type_name -> v2ray.core.proxy.freedom.Config.DomainStrategy
|
1, // 1: v2ray.core.proxy.freedom.Config.domain_strategy:type_name -> v2ray.core.proxy.freedom.Config.DomainStrategy
|
||||||
1, // 2: v2ray.core.proxy.freedom.Config.destination_override:type_name -> v2ray.core.proxy.freedom.DestinationOverride
|
2, // 2: v2ray.core.proxy.freedom.Config.destination_override:type_name -> v2ray.core.proxy.freedom.DestinationOverride
|
||||||
3, // [3:3] is the sub-list for method output_type
|
0, // 3: v2ray.core.proxy.freedom.Config.protocol_replacement:type_name -> v2ray.core.proxy.freedom.ProtocolReplacement
|
||||||
3, // [3:3] is the sub-list for method input_type
|
2, // 4: v2ray.core.proxy.freedom.SimplifiedConfig.destination_override:type_name -> v2ray.core.proxy.freedom.DestinationOverride
|
||||||
3, // [3:3] is the sub-list for extension type_name
|
0, // 5: v2ray.core.proxy.freedom.SimplifiedConfig.protocol_replacement:type_name -> v2ray.core.proxy.freedom.ProtocolReplacement
|
||||||
3, // [3:3] is the sub-list for extension extendee
|
6, // [6:6] is the sub-list for method output_type
|
||||||
0, // [0:3] is the sub-list for field type_name
|
6, // [6:6] is the sub-list for method input_type
|
||||||
|
6, // [6:6] is the sub-list for extension type_name
|
||||||
|
6, // [6:6] is the sub-list for extension extendee
|
||||||
|
0, // [0:6] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_proxy_freedom_config_proto_init() }
|
func init() { file_proxy_freedom_config_proto_init() }
|
||||||
@ -313,7 +414,7 @@ func file_proxy_freedom_config_proto_init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !protoimpl.UnsafeEnabled {
|
if !protoimpl.UnsafeEnabled {
|
||||||
file_proxy_freedom_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
file_proxy_freedom_config_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*DestinationOverride); i {
|
switch v := v.(*DestinationOverride); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@ -325,7 +426,7 @@ func file_proxy_freedom_config_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_proxy_freedom_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
file_proxy_freedom_config_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*Config); i {
|
switch v := v.(*Config); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@ -337,7 +438,7 @@ func file_proxy_freedom_config_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_proxy_freedom_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
file_proxy_freedom_config_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*SimplifiedConfig); i {
|
switch v := v.(*SimplifiedConfig); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@ -355,7 +456,7 @@ func file_proxy_freedom_config_proto_init() {
|
|||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_proxy_freedom_config_proto_rawDesc,
|
RawDescriptor: file_proxy_freedom_config_proto_rawDesc,
|
||||||
NumEnums: 1,
|
NumEnums: 2,
|
||||||
NumMessages: 3,
|
NumMessages: 3,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
|
@ -13,6 +13,12 @@ message DestinationOverride {
|
|||||||
v2ray.core.common.protocol.ServerEndpoint server = 1;
|
v2ray.core.common.protocol.ServerEndpoint server = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ProtocolReplacement {
|
||||||
|
IDENTITY = 0;
|
||||||
|
FORCE_TCP = 1;
|
||||||
|
FORCE_UDP = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message Config {
|
message Config {
|
||||||
enum DomainStrategy {
|
enum DomainStrategy {
|
||||||
AS_IS = 0;
|
AS_IS = 0;
|
||||||
@ -24,9 +30,13 @@ message Config {
|
|||||||
uint32 timeout = 2 [deprecated = true];
|
uint32 timeout = 2 [deprecated = true];
|
||||||
DestinationOverride destination_override = 3;
|
DestinationOverride destination_override = 3;
|
||||||
uint32 user_level = 4;
|
uint32 user_level = 4;
|
||||||
|
ProtocolReplacement protocol_replacement = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SimplifiedConfig {
|
message SimplifiedConfig {
|
||||||
option (v2ray.core.common.protoext.message_opt).type = "outbound";
|
option (v2ray.core.common.protoext.message_opt).type = "outbound";
|
||||||
option (v2ray.core.common.protoext.message_opt).short_name = "freedom";
|
option (v2ray.core.common.protoext.message_opt).short_name = "freedom";
|
||||||
|
|
||||||
|
DestinationOverride destination_override = 3;
|
||||||
|
ProtocolReplacement protocol_replacement = 5;
|
||||||
}
|
}
|
@ -35,7 +35,10 @@ func init() {
|
|||||||
common.Must(common.RegisterConfig((*SimplifiedConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
common.Must(common.RegisterConfig((*SimplifiedConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
simplifiedServer := config.(*SimplifiedConfig)
|
simplifiedServer := config.(*SimplifiedConfig)
|
||||||
_ = simplifiedServer
|
_ = simplifiedServer
|
||||||
fullConfig := &Config{}
|
fullConfig := &Config{
|
||||||
|
DestinationOverride: simplifiedServer.DestinationOverride,
|
||||||
|
ProtocolReplacement: simplifiedServer.ProtocolReplacement,
|
||||||
|
}
|
||||||
return common.CreateObject(ctx, fullConfig)
|
return common.CreateObject(ctx, fullConfig)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -104,6 +107,14 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
destination.Port = net.Port(server.Port)
|
destination.Port = net.Port(server.Port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if h.config.ProtocolReplacement != ProtocolReplacement_IDENTITY {
|
||||||
|
if h.config.ProtocolReplacement == ProtocolReplacement_FORCE_TCP {
|
||||||
|
destination.Network = net.Network_TCP
|
||||||
|
}
|
||||||
|
if h.config.ProtocolReplacement == ProtocolReplacement_FORCE_UDP {
|
||||||
|
destination.Network = net.Network_UDP
|
||||||
|
}
|
||||||
|
}
|
||||||
if h.config.useIP() {
|
if h.config.useIP() {
|
||||||
outbound.Resolver = func(ctx context.Context, domain string) net.Address {
|
outbound.Resolver = func(ctx context.Context, domain string) net.Address {
|
||||||
return h.resolveIP(ctx, domain, dialer.Address())
|
return h.resolveIP(ctx, domain, dialer.Address())
|
||||||
@ -153,7 +164,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
|
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
|
||||||
|
|
||||||
var reader buf.Reader
|
var reader buf.Reader
|
||||||
if destination.Network == net.Network_TCP {
|
if destination.Network == net.Network_TCP && h.config.ProtocolReplacement == ProtocolReplacement_IDENTITY {
|
||||||
reader = buf.NewReader(conn)
|
reader = buf.NewReader(conn)
|
||||||
} else {
|
} else {
|
||||||
reader = buf.NewPacketReader(conn)
|
reader = buf.NewPacketReader(conn)
|
||||||
|
236
transport/internet/dtls/config.pb.go
Normal file
236
transport/internet/dtls/config.pb.go
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
package dtls
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/v2fly/v2ray-core/v5/common/protoext"
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type DTLSMode int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
DTLSMode_INVALID DTLSMode = 0
|
||||||
|
DTLSMode_PSK DTLSMode = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for DTLSMode.
|
||||||
|
var (
|
||||||
|
DTLSMode_name = map[int32]string{
|
||||||
|
0: "INVALID",
|
||||||
|
1: "PSK",
|
||||||
|
}
|
||||||
|
DTLSMode_value = map[string]int32{
|
||||||
|
"INVALID": 0,
|
||||||
|
"PSK": 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x DTLSMode) Enum() *DTLSMode {
|
||||||
|
p := new(DTLSMode)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x DTLSMode) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DTLSMode) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_transport_internet_dtls_config_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DTLSMode) Type() protoreflect.EnumType {
|
||||||
|
return &file_transport_internet_dtls_config_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x DTLSMode) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use DTLSMode.Descriptor instead.
|
||||||
|
func (DTLSMode) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_transport_internet_dtls_config_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Mode DTLSMode `protobuf:"varint,1,opt,name=mode,proto3,enum=v2ray.core.transport.internet.dtls.DTLSMode" json:"mode,omitempty"`
|
||||||
|
Psk []byte `protobuf:"bytes,2,opt,name=psk,proto3" json:"psk,omitempty"`
|
||||||
|
Mtu uint32 `protobuf:"varint,3,opt,name=mtu,proto3" json:"mtu,omitempty"`
|
||||||
|
ReplayProtectionWindow uint32 `protobuf:"varint,4,opt,name=replay_protection_window,json=replayProtectionWindow,proto3" json:"replay_protection_window,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) Reset() {
|
||||||
|
*x = Config{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_transport_internet_dtls_config_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Config) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_transport_internet_dtls_config_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Config) Descriptor() ([]byte, []int) {
|
||||||
|
return file_transport_internet_dtls_config_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetMode() DTLSMode {
|
||||||
|
if x != nil {
|
||||||
|
return x.Mode
|
||||||
|
}
|
||||||
|
return DTLSMode_INVALID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetPsk() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Psk
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetMtu() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Mtu
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetReplayProtectionWindow() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.ReplayProtectionWindow
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_transport_internet_dtls_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_transport_internet_dtls_config_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x24, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
|
||||||
|
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x22, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||||
|
0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,
|
||||||
|
0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x64, 0x74, 0x6c, 0x73, 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, 0xbf, 0x01, 0x0a,
|
||||||
|
0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x40, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18,
|
||||||
|
0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||||
|
0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,
|
||||||
|
0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x64, 0x74, 0x6c, 0x73, 0x2e, 0x44, 0x54, 0x4c, 0x53, 0x4d,
|
||||||
|
0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x73, 0x6b,
|
||||||
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x70, 0x73, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x6d,
|
||||||
|
0x74, 0x75, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x12, 0x38, 0x0a,
|
||||||
|
0x18, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69,
|
||||||
|
0x6f, 0x6e, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
||||||
|
0x16, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||||
|
0x6e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x3a, 0x15, 0x82, 0xb5, 0x18, 0x11, 0x0a, 0x09, 0x74,
|
||||||
|
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x04, 0x64, 0x74, 0x6c, 0x73, 0x2a, 0x20,
|
||||||
|
0x0a, 0x08, 0x44, 0x54, 0x4c, 0x53, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e,
|
||||||
|
0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x53, 0x4b, 0x10, 0x01,
|
||||||
|
0x42, 0x87, 0x01, 0x0a, 0x26, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||||
|
0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
|
||||||
|
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x64, 0x74, 0x6c, 0x73, 0x50, 0x01, 0x5a, 0x36, 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, 0x74, 0x72,
|
||||||
|
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
||||||
|
0x2f, 0x64, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x22, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f,
|
||||||
|
0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74,
|
||||||
|
0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x74, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_transport_internet_dtls_config_proto_rawDescOnce sync.Once
|
||||||
|
file_transport_internet_dtls_config_proto_rawDescData = file_transport_internet_dtls_config_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_transport_internet_dtls_config_proto_rawDescGZIP() []byte {
|
||||||
|
file_transport_internet_dtls_config_proto_rawDescOnce.Do(func() {
|
||||||
|
file_transport_internet_dtls_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_dtls_config_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_transport_internet_dtls_config_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_transport_internet_dtls_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
|
var file_transport_internet_dtls_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||||
|
var file_transport_internet_dtls_config_proto_goTypes = []any{
|
||||||
|
(DTLSMode)(0), // 0: v2ray.core.transport.internet.dtls.DTLSMode
|
||||||
|
(*Config)(nil), // 1: v2ray.core.transport.internet.dtls.Config
|
||||||
|
}
|
||||||
|
var file_transport_internet_dtls_config_proto_depIdxs = []int32{
|
||||||
|
0, // 0: v2ray.core.transport.internet.dtls.Config.mode:type_name -> v2ray.core.transport.internet.dtls.DTLSMode
|
||||||
|
1, // [1:1] is the sub-list for method output_type
|
||||||
|
1, // [1:1] is the sub-list for method input_type
|
||||||
|
1, // [1:1] is the sub-list for extension type_name
|
||||||
|
1, // [1:1] is the sub-list for extension extendee
|
||||||
|
0, // [0:1] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_transport_internet_dtls_config_proto_init() }
|
||||||
|
func file_transport_internet_dtls_config_proto_init() {
|
||||||
|
if File_transport_internet_dtls_config_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_transport_internet_dtls_config_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*Config); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_transport_internet_dtls_config_proto_rawDesc,
|
||||||
|
NumEnums: 1,
|
||||||
|
NumMessages: 1,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_transport_internet_dtls_config_proto_goTypes,
|
||||||
|
DependencyIndexes: file_transport_internet_dtls_config_proto_depIdxs,
|
||||||
|
EnumInfos: file_transport_internet_dtls_config_proto_enumTypes,
|
||||||
|
MessageInfos: file_transport_internet_dtls_config_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_transport_internet_dtls_config_proto = out.File
|
||||||
|
file_transport_internet_dtls_config_proto_rawDesc = nil
|
||||||
|
file_transport_internet_dtls_config_proto_goTypes = nil
|
||||||
|
file_transport_internet_dtls_config_proto_depIdxs = nil
|
||||||
|
}
|
25
transport/internet/dtls/config.proto
Normal file
25
transport/internet/dtls/config.proto
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package v2ray.core.transport.internet.dtls;
|
||||||
|
option csharp_namespace = "V2Ray.Core.Transport.Internet.Dtls";
|
||||||
|
option go_package = "github.com/v2fly/v2ray-core/v5/transport/internet/dtls";
|
||||||
|
option java_package = "com.v2ray.core.transport.internet.dtls";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "common/protoext/extensions.proto";
|
||||||
|
|
||||||
|
enum DTLSMode {
|
||||||
|
INVALID = 0;
|
||||||
|
PSK = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Config {
|
||||||
|
option (v2ray.core.common.protoext.message_opt).type = "transport";
|
||||||
|
option (v2ray.core.common.protoext.message_opt).short_name = "dtls";
|
||||||
|
|
||||||
|
DTLSMode mode = 1;
|
||||||
|
bytes psk = 2;
|
||||||
|
|
||||||
|
uint32 mtu = 3;
|
||||||
|
uint32 replay_protection_window = 4;
|
||||||
|
}
|
57
transport/internet/dtls/dialer.go
Normal file
57
transport/internet/dtls/dialer.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package dtls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/pion/dtls/v2"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/net"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/session"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/transport/internet"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dialDTLS(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (net.Conn, error) {
|
||||||
|
transportConfiguration := streamSettings.ProtocolSettings.(*Config)
|
||||||
|
|
||||||
|
newError("dialing DTLS to ", dest).WriteToLog()
|
||||||
|
|
||||||
|
transportEnvironment := envctx.EnvironmentFromContext(ctx).(environment.TransportEnvironment)
|
||||||
|
dialer := transportEnvironment.Dialer()
|
||||||
|
|
||||||
|
rawConn, err := dialer.Dial(ctx, nil, dest, streamSettings.SocketSettings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("failed to dial to dest: ", err).AtWarning().Base(err)
|
||||||
|
}
|
||||||
|
config := &dtls.Config{}
|
||||||
|
config.MTU = int(transportConfiguration.Mtu)
|
||||||
|
config.ReplayProtectionWindow = int(transportConfiguration.ReplayProtectionWindow)
|
||||||
|
|
||||||
|
switch transportConfiguration.Mode {
|
||||||
|
case DTLSMode_PSK:
|
||||||
|
config.PSK = func(bytes []byte) ([]byte, error) {
|
||||||
|
return transportConfiguration.Psk, nil
|
||||||
|
}
|
||||||
|
config.PSKIdentityHint = []byte("")
|
||||||
|
config.CipherSuites = []dtls.CipherSuiteID{dtls.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256}
|
||||||
|
default:
|
||||||
|
return nil, newError("unknow dtls mode")
|
||||||
|
}
|
||||||
|
return dtls.Client(rawConn, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {
|
||||||
|
newError("creating connection to ", dest).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
|
||||||
|
conn, err := dialDTLS(ctx, dest, streamSettings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("failed to dial request to ", dest).Base(err)
|
||||||
|
}
|
||||||
|
return internet.Connection(conn), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.Must(internet.RegisterTransportDialer(protocolName, dial))
|
||||||
|
}
|
16
transport/internet/dtls/dtls.go
Normal file
16
transport/internet/dtls/dtls.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package dtls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/transport/internet"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
|
||||||
|
|
||||||
|
const protocolName = "dtls"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
|
||||||
|
return new(Config)
|
||||||
|
}))
|
||||||
|
}
|
9
transport/internet/dtls/errors.generated.go
Normal file
9
transport/internet/dtls/errors.generated.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package dtls
|
||||||
|
|
||||||
|
import "github.com/v2fly/v2ray-core/v5/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
212
transport/internet/dtls/listener.go
Normal file
212
transport/internet/dtls/listener.go
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
package dtls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
gonet "net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pion/dtls/v2"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/buf"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/net"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/transport/internet"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/transport/internet/udp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Listener struct {
|
||||||
|
config *Config
|
||||||
|
|
||||||
|
sync.Mutex
|
||||||
|
addConn internet.ConnHandler
|
||||||
|
hub *udp.Hub
|
||||||
|
|
||||||
|
sessions map[ConnectionID]*dTLSConnWrapped
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) Close() error {
|
||||||
|
return l.hub.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) Addr() net.Addr {
|
||||||
|
return l.hub.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectionID struct {
|
||||||
|
Remote net.Address
|
||||||
|
Port net.Port
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDTLSServerConn(src net.Destination, parent *Listener) *dTLSConn {
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx, finish := context.WithCancel(ctx)
|
||||||
|
return &dTLSConn{
|
||||||
|
src: src,
|
||||||
|
parent: parent,
|
||||||
|
readChan: make(chan *buf.Buffer, 256),
|
||||||
|
ctx: ctx,
|
||||||
|
finish: finish,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type dTLSConnWrapped struct {
|
||||||
|
unencryptedConn *dTLSConn
|
||||||
|
dTLSConn *dtls.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
type dTLSConn struct {
|
||||||
|
src net.Destination
|
||||||
|
parent *Listener
|
||||||
|
|
||||||
|
readChan chan *buf.Buffer
|
||||||
|
ctx context.Context
|
||||||
|
finish func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *dTLSConn) Read(b []byte) (n int, err error) {
|
||||||
|
select {
|
||||||
|
case pack := <-l.readChan:
|
||||||
|
n := copy(b, pack.Bytes())
|
||||||
|
defer pack.Release()
|
||||||
|
if n < int(pack.Len()) {
|
||||||
|
return n, io.ErrShortBuffer
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
case <-l.ctx.Done():
|
||||||
|
return 0, l.ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *dTLSConn) Write(b []byte) (n int, err error) {
|
||||||
|
return l.parent.hub.WriteTo(b, l.src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *dTLSConn) Close() error {
|
||||||
|
l.finish()
|
||||||
|
l.parent.Remove(l.src)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *dTLSConn) LocalAddr() gonet.Addr {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *dTLSConn) RemoteAddr() gonet.Addr {
|
||||||
|
return &net.UDPAddr{
|
||||||
|
IP: l.src.Address.IP(),
|
||||||
|
Port: int(l.src.Port.Value()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *dTLSConn) SetDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *dTLSConn) SetReadDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *dTLSConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *dTLSConn) OnReceive(payload *buf.Buffer) {
|
||||||
|
select {
|
||||||
|
case l.readChan <- payload:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListener(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (*Listener, error) {
|
||||||
|
transportConfiguration := streamSettings.ProtocolSettings.(*Config)
|
||||||
|
hub, err := udp.ListenUDP(ctx, address, port, streamSettings, udp.HubCapacity(1024))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l := &Listener{
|
||||||
|
addConn: addConn,
|
||||||
|
config: transportConfiguration,
|
||||||
|
sessions: make(map[ConnectionID]*dTLSConnWrapped),
|
||||||
|
}
|
||||||
|
l.Lock()
|
||||||
|
l.hub = hub
|
||||||
|
l.Unlock()
|
||||||
|
newError("listening on ", address, ":", port).WriteToLog()
|
||||||
|
|
||||||
|
go l.handlePackets()
|
||||||
|
return l, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) handlePackets() {
|
||||||
|
receive := l.hub.Receive()
|
||||||
|
for payload := range receive {
|
||||||
|
l.OnReceive(payload.Payload, payload.Source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDTLSConnWrapped(unencryptedConnection *dTLSConn, transportConfiguration *Config) (*dtls.Conn, error) {
|
||||||
|
config := &dtls.Config{}
|
||||||
|
config.MTU = int(transportConfiguration.Mtu)
|
||||||
|
config.ReplayProtectionWindow = int(transportConfiguration.ReplayProtectionWindow)
|
||||||
|
|
||||||
|
switch transportConfiguration.Mode {
|
||||||
|
case DTLSMode_PSK:
|
||||||
|
config.PSK = func(bytes []byte) ([]byte, error) {
|
||||||
|
return transportConfiguration.Psk, nil
|
||||||
|
}
|
||||||
|
config.PSKIdentityHint = []byte("")
|
||||||
|
config.CipherSuites = []dtls.CipherSuiteID{dtls.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256}
|
||||||
|
default:
|
||||||
|
newError("unknown dtls mode").WriteToLog()
|
||||||
|
}
|
||||||
|
dtlsConn, err := dtls.Server(unencryptedConnection, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("unable to create dtls server conn").Base(err)
|
||||||
|
}
|
||||||
|
return dtlsConn, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) OnReceive(payload *buf.Buffer, src net.Destination) {
|
||||||
|
id := ConnectionID{
|
||||||
|
Remote: src.Address,
|
||||||
|
Port: src.Port,
|
||||||
|
}
|
||||||
|
l.Lock()
|
||||||
|
defer l.Unlock()
|
||||||
|
conn, found := l.sessions[id]
|
||||||
|
if !found {
|
||||||
|
var err error
|
||||||
|
unEncryptedConn := newDTLSServerConn(src, l)
|
||||||
|
conn = &dTLSConnWrapped{unencryptedConn: unEncryptedConn}
|
||||||
|
l.sessions[id] = conn
|
||||||
|
go func() {
|
||||||
|
conn.dTLSConn, err = newDTLSConnWrapped(unEncryptedConn, l.config)
|
||||||
|
if err != nil {
|
||||||
|
newError("unable to accept new dtls connection").Base(err).WriteToLog()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l.addConn(internet.Connection(conn.dTLSConn))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
conn.unencryptedConn.OnReceive(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) Remove(src net.Destination) {
|
||||||
|
l.Lock()
|
||||||
|
defer l.Unlock()
|
||||||
|
id := ConnectionID{
|
||||||
|
Remote: src.Address,
|
||||||
|
Port: src.Port,
|
||||||
|
}
|
||||||
|
delete(l.sessions, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListenDTLS(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (internet.Listener, error) {
|
||||||
|
return NewListener(ctx, address, port, streamSettings, addConn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.Must(internet.RegisterTransportListener(protocolName, ListenDTLS))
|
||||||
|
}
|
@ -8,6 +8,8 @@ import (
|
|||||||
"github.com/v2fly/v2ray-core/v5/common"
|
"github.com/v2fly/v2ray-core/v5/common"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/buf"
|
"github.com/v2fly/v2ray-core/v5/common/buf"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/dice"
|
"github.com/v2fly/v2ray-core/v5/common/dice"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/net"
|
"github.com/v2fly/v2ray-core/v5/common/net"
|
||||||
"github.com/v2fly/v2ray-core/v5/transport/internet"
|
"github.com/v2fly/v2ray-core/v5/transport/internet"
|
||||||
"github.com/v2fly/v2ray-core/v5/transport/internet/tls"
|
"github.com/v2fly/v2ray-core/v5/transport/internet/tls"
|
||||||
@ -47,7 +49,10 @@ func DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet
|
|||||||
dest.Network = net.Network_UDP
|
dest.Network = net.Network_UDP
|
||||||
newError("dialing mKCP to ", dest).WriteToLog()
|
newError("dialing mKCP to ", dest).WriteToLog()
|
||||||
|
|
||||||
rawConn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
|
transportEnvironment := envctx.EnvironmentFromContext(ctx).(environment.TransportEnvironment)
|
||||||
|
dialer := transportEnvironment.Dialer()
|
||||||
|
|
||||||
|
rawConn, err := dialer.Dial(ctx, nil, dest, streamSettings.SocketSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("failed to dial to dest: ", err).AtWarning().Base(err)
|
return nil, newError("failed to dial to dest: ", err).AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/systemnetworkimpl"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/transientstorageimpl"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
@ -18,7 +23,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestDialAndListen(t *testing.T) {
|
func TestDialAndListen(t *testing.T) {
|
||||||
listener, err := NewListener(context.Background(), net.LocalHostIP, net.Port(0), &internet.MemoryStreamConfig{
|
ctx := context.Background()
|
||||||
|
defaultNetworkImpl := systemnetworkimpl.NewSystemNetworkDefault()
|
||||||
|
rootEnv := environment.NewRootEnvImpl(ctx, transientstorageimpl.NewScopedTransientStorageImpl(), defaultNetworkImpl.Dialer(), defaultNetworkImpl.Listener())
|
||||||
|
proxyEnvironment := rootEnv.ProxyEnvironment("o")
|
||||||
|
transportEnvironment, err := proxyEnvironment.NarrowScopeToTransport("kcp")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx = envctx.ContextWithEnvironment(ctx, transportEnvironment)
|
||||||
|
|
||||||
|
listener, err := NewListener(ctx, net.LocalHostIP, net.Port(0), &internet.MemoryStreamConfig{
|
||||||
ProtocolName: "mkcp",
|
ProtocolName: "mkcp",
|
||||||
ProtocolSettings: &Config{},
|
ProtocolSettings: &Config{},
|
||||||
}, func(conn internet.Connection) {
|
}, func(conn internet.Connection) {
|
||||||
@ -45,7 +60,7 @@ func TestDialAndListen(t *testing.T) {
|
|||||||
var errg errgroup.Group
|
var errg errgroup.Group
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
errg.Go(func() error {
|
errg.Go(func() error {
|
||||||
clientConn, err := DialKCP(context.Background(), net.UDPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{
|
clientConn, err := DialKCP(ctx, net.UDPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{
|
||||||
ProtocolName: "mkcp",
|
ProtocolName: "mkcp",
|
||||||
ProtocolSettings: &Config{},
|
ProtocolSettings: &Config{},
|
||||||
})
|
})
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package packetconn
|
||||||
|
|
||||||
|
import "github.com/v2fly/v2ray-core/v5/common/errors"
|
||||||
|
|
||||||
|
type errPathObjHolder struct{}
|
||||||
|
|
||||||
|
func newError(values ...interface{}) *errors.Error {
|
||||||
|
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||||
|
}
|
342
transport/internet/request/assembler/packetconn/packetConn.pb.go
Normal file
342
transport/internet/request/assembler/packetconn/packetConn.pb.go
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
package packetconn
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/v2fly/v2ray-core/v5/common/protoext"
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClientConfig struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
UnderlyingTransportSetting *anypb.Any `protobuf:"bytes,1,opt,name=underlying_transport_setting,json=underlyingTransportSetting,proto3" json:"underlying_transport_setting,omitempty"`
|
||||||
|
UnderlyingTransportName string `protobuf:"bytes,2,opt,name=underlying_transport_name,json=underlyingTransportName,proto3" json:"underlying_transport_name,omitempty"`
|
||||||
|
MaxWriteDelay int32 `protobuf:"varint,3,opt,name=max_write_delay,json=maxWriteDelay,proto3" json:"max_write_delay,omitempty"`
|
||||||
|
MaxRequestSize int32 `protobuf:"varint,4,opt,name=max_request_size,json=maxRequestSize,proto3" json:"max_request_size,omitempty"`
|
||||||
|
PollingIntervalInitial int32 `protobuf:"varint,5,opt,name=polling_interval_initial,json=pollingIntervalInitial,proto3" json:"polling_interval_initial,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ClientConfig) Reset() {
|
||||||
|
*x = ClientConfig{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_transport_internet_request_assembler_packetconn_packetConn_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ClientConfig) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ClientConfig) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ClientConfig) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_transport_internet_request_assembler_packetconn_packetConn_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ClientConfig) Descriptor() ([]byte, []int) {
|
||||||
|
return file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ClientConfig) GetUnderlyingTransportSetting() *anypb.Any {
|
||||||
|
if x != nil {
|
||||||
|
return x.UnderlyingTransportSetting
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ClientConfig) GetUnderlyingTransportName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.UnderlyingTransportName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ClientConfig) GetMaxWriteDelay() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MaxWriteDelay
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ClientConfig) GetMaxRequestSize() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MaxRequestSize
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ClientConfig) GetPollingIntervalInitial() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.PollingIntervalInitial
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerConfig struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
UnderlyingTransportSetting *anypb.Any `protobuf:"bytes,1,opt,name=underlying_transport_setting,json=underlyingTransportSetting,proto3" json:"underlying_transport_setting,omitempty"`
|
||||||
|
UnderlyingTransportName string `protobuf:"bytes,2,opt,name=underlying_transport_name,json=underlyingTransportName,proto3" json:"underlying_transport_name,omitempty"`
|
||||||
|
MaxWriteSize int32 `protobuf:"varint,3,opt,name=max_write_size,json=maxWriteSize,proto3" json:"max_write_size,omitempty"`
|
||||||
|
MaxWriteDurationMs int32 `protobuf:"varint,4,opt,name=max_write_duration_ms,json=maxWriteDurationMs,proto3" json:"max_write_duration_ms,omitempty"`
|
||||||
|
MaxSimultaneousWriteConnection int32 `protobuf:"varint,5,opt,name=max_simultaneous_write_connection,json=maxSimultaneousWriteConnection,proto3" json:"max_simultaneous_write_connection,omitempty"`
|
||||||
|
PacketWritingBuffer int32 `protobuf:"varint,6,opt,name=packet_writing_buffer,json=packetWritingBuffer,proto3" json:"packet_writing_buffer,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerConfig) Reset() {
|
||||||
|
*x = ServerConfig{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_transport_internet_request_assembler_packetconn_packetConn_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerConfig) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ServerConfig) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ServerConfig) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_transport_internet_request_assembler_packetconn_packetConn_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ServerConfig) Descriptor() ([]byte, []int) {
|
||||||
|
return file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerConfig) GetUnderlyingTransportSetting() *anypb.Any {
|
||||||
|
if x != nil {
|
||||||
|
return x.UnderlyingTransportSetting
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerConfig) GetUnderlyingTransportName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.UnderlyingTransportName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerConfig) GetMaxWriteSize() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MaxWriteSize
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerConfig) GetMaxWriteDurationMs() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MaxWriteDurationMs
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerConfig) GetMaxSimultaneousWriteConnection() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MaxSimultaneousWriteConnection
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerConfig) GetPacketWritingBuffer() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.PacketWritingBuffer
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_transport_internet_request_assembler_packetconn_packetConn_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x40, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
|
||||||
|
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2f, 0x61, 0x73, 0x73,
|
||||||
|
0x65, 0x6d, 0x62, 0x6c, 0x65, 0x72, 0x2f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x63, 0x6f, 0x6e,
|
||||||
|
0x6e, 0x2f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
|
0x74, 0x6f, 0x12, 0x3a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74,
|
||||||
|
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
|
||||||
|
0x74, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x6d, 0x62,
|
||||||
|
0x6c, 0x65, 0x72, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x63, 0x6f, 0x6e, 0x6e, 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,
|
||||||
|
0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||||
|
0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe4, 0x02, 0x0a, 0x0c,
|
||||||
|
0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x56, 0x0a, 0x1c,
|
||||||
|
0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73,
|
||||||
|
0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01,
|
||||||
|
0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x1a, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c,
|
||||||
|
0x79, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74,
|
||||||
|
0x74, 0x69, 0x6e, 0x67, 0x12, 0x3a, 0x0a, 0x19, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x79, 0x69,
|
||||||
|
0x6e, 0x67, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d,
|
||||||
|
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x79,
|
||||||
|
0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65,
|
||||||
|
0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65,
|
||||||
|
0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x57, 0x72,
|
||||||
|
0x69, 0x74, 0x65, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f,
|
||||||
|
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01,
|
||||||
|
0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x69,
|
||||||
|
0x7a, 0x65, 0x12, 0x38, 0x0a, 0x18, 0x70, 0x6f, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x6e,
|
||||||
|
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x05,
|
||||||
|
0x20, 0x01, 0x28, 0x05, 0x52, 0x16, 0x70, 0x6f, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x74,
|
||||||
|
0x65, 0x72, 0x76, 0x61, 0x6c, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x3a, 0x34, 0x82, 0xb5,
|
||||||
|
0x18, 0x30, 0x0a, 0x22, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x72, 0x65,
|
||||||
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x72, 0x2e,
|
||||||
|
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x0a, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x63, 0x6f,
|
||||||
|
0x6e, 0x6e, 0x22, 0xb0, 0x03, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e,
|
||||||
|
0x66, 0x69, 0x67, 0x12, 0x56, 0x0a, 0x1c, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x79, 0x69, 0x6e,
|
||||||
|
0x67, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x74,
|
||||||
|
0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||||
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52,
|
||||||
|
0x1a, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73,
|
||||||
|
0x70, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x3a, 0x0a, 0x19, 0x75,
|
||||||
|
0x6e, 0x64, 0x65, 0x72, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
|
||||||
|
0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17,
|
||||||
|
0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70,
|
||||||
|
0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x77,
|
||||||
|
0x72, 0x69, 0x74, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||||
|
0x0c, 0x6d, 0x61, 0x78, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x31, 0x0a,
|
||||||
|
0x15, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74,
|
||||||
|
0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x6d, 0x61,
|
||||||
|
0x78, 0x57, 0x72, 0x69, 0x74, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73,
|
||||||
|
0x12, 0x49, 0x0a, 0x21, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x74, 0x61, 0x6e,
|
||||||
|
0x65, 0x6f, 0x75, 0x73, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
|
||||||
|
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1e, 0x6d, 0x61, 0x78,
|
||||||
|
0x53, 0x69, 0x6d, 0x75, 0x6c, 0x74, 0x61, 0x6e, 0x65, 0x6f, 0x75, 0x73, 0x57, 0x72, 0x69, 0x74,
|
||||||
|
0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x70,
|
||||||
|
0x61, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x75,
|
||||||
|
0x66, 0x66, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x70, 0x61, 0x63, 0x6b,
|
||||||
|
0x65, 0x74, 0x57, 0x72, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x3a,
|
||||||
|
0x34, 0x82, 0xb5, 0x18, 0x30, 0x0a, 0x22, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
|
||||||
|
0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c,
|
||||||
|
0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x0a, 0x70, 0x61, 0x63, 0x6b, 0x65,
|
||||||
|
0x74, 0x63, 0x6f, 0x6e, 0x6e, 0x42, 0xcf, 0x01, 0x0a, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32,
|
||||||
|
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
|
||||||
|
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x71, 0x75,
|
||||||
|
0x65, 0x73, 0x74, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x72, 0x2e, 0x70, 0x61,
|
||||||
|
0x63, 0x6b, 0x65, 0x74, 0x63, 0x6f, 0x6e, 0x6e, 0x50, 0x01, 0x5a, 0x4e, 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, 0x74, 0x72, 0x61, 0x6e, 0x73,
|
||||||
|
0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x65,
|
||||||
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x2f, 0x61, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x72, 0x2f,
|
||||||
|
0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x63, 0x6f, 0x6e, 0x6e, 0xaa, 0x02, 0x3a, 0x56, 0x32, 0x52,
|
||||||
|
0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
||||||
|
0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||||
|
0x73, 0x74, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x63,
|
||||||
|
0x6b, 0x65, 0x74, 0x63, 0x6f, 0x6e, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDescOnce sync.Once
|
||||||
|
file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDescData = file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDescGZIP() []byte {
|
||||||
|
file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDescOnce.Do(func() {
|
||||||
|
file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_transport_internet_request_assembler_packetconn_packetConn_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
|
var file_transport_internet_request_assembler_packetconn_packetConn_proto_goTypes = []any{
|
||||||
|
(*ClientConfig)(nil), // 0: v2ray.core.transport.internet.request.assembler.packetconn.ClientConfig
|
||||||
|
(*ServerConfig)(nil), // 1: v2ray.core.transport.internet.request.assembler.packetconn.ServerConfig
|
||||||
|
(*anypb.Any)(nil), // 2: google.protobuf.Any
|
||||||
|
}
|
||||||
|
var file_transport_internet_request_assembler_packetconn_packetConn_proto_depIdxs = []int32{
|
||||||
|
2, // 0: v2ray.core.transport.internet.request.assembler.packetconn.ClientConfig.underlying_transport_setting:type_name -> google.protobuf.Any
|
||||||
|
2, // 1: v2ray.core.transport.internet.request.assembler.packetconn.ServerConfig.underlying_transport_setting:type_name -> google.protobuf.Any
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_transport_internet_request_assembler_packetconn_packetConn_proto_init() }
|
||||||
|
func file_transport_internet_request_assembler_packetconn_packetConn_proto_init() {
|
||||||
|
if File_transport_internet_request_assembler_packetconn_packetConn_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_transport_internet_request_assembler_packetconn_packetConn_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*ClientConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_transport_internet_request_assembler_packetconn_packetConn_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*ServerConfig); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 2,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_transport_internet_request_assembler_packetconn_packetConn_proto_goTypes,
|
||||||
|
DependencyIndexes: file_transport_internet_request_assembler_packetconn_packetConn_proto_depIdxs,
|
||||||
|
MessageInfos: file_transport_internet_request_assembler_packetconn_packetConn_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_transport_internet_request_assembler_packetconn_packetConn_proto = out.File
|
||||||
|
file_transport_internet_request_assembler_packetconn_packetConn_proto_rawDesc = nil
|
||||||
|
file_transport_internet_request_assembler_packetconn_packetConn_proto_goTypes = nil
|
||||||
|
file_transport_internet_request_assembler_packetconn_packetConn_proto_depIdxs = nil
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package v2ray.core.transport.internet.request.assembler.packetconn;
|
||||||
|
option csharp_namespace = "V2Ray.Core.Transport.Internet.Request.Assembler.Packetconn";
|
||||||
|
option go_package = "github.com/v2fly/v2ray-core/v5/transport/internet/request/assembler/packetconn";
|
||||||
|
option java_package = "com.v2ray.core.transport.internet.request.assembler.packetconn";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "common/protoext/extensions.proto";
|
||||||
|
import "google/protobuf/any.proto";
|
||||||
|
|
||||||
|
message ClientConfig {
|
||||||
|
option (v2ray.core.common.protoext.message_opt).type = "transport.request.assembler.client";
|
||||||
|
option (v2ray.core.common.protoext.message_opt).short_name = "packetconn";
|
||||||
|
|
||||||
|
google.protobuf.Any underlying_transport_setting = 1;
|
||||||
|
string underlying_transport_name = 2;
|
||||||
|
|
||||||
|
int32 max_write_delay = 3;
|
||||||
|
int32 max_request_size = 4;
|
||||||
|
int32 polling_interval_initial = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ServerConfig {
|
||||||
|
option (v2ray.core.common.protoext.message_opt).type = "transport.request.assembler.server";
|
||||||
|
option (v2ray.core.common.protoext.message_opt).short_name = "packetconn";
|
||||||
|
|
||||||
|
google.protobuf.Any underlying_transport_setting = 1;
|
||||||
|
string underlying_transport_name = 2;
|
||||||
|
|
||||||
|
int32 max_write_size = 3;
|
||||||
|
int32 max_write_duration_ms = 4;
|
||||||
|
int32 max_simultaneous_write_connection = 5;
|
||||||
|
int32 packet_writing_buffer = 6;
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package packetconn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewPacketBundle() PacketBundle {
|
||||||
|
return &packetBundle{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type packetBundle struct{}
|
||||||
|
|
||||||
|
func (p *packetBundle) Overhead() int {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *packetBundle) WriteToBundle(b []byte, writer io.Writer) (err error) {
|
||||||
|
err = binary.Write(writer, binary.BigEndian, uint16(len(b)))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = writer.Write(b)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *packetBundle) ReadFromBundle(writer io.Reader) (b []byte, err error) {
|
||||||
|
var length uint16
|
||||||
|
err = binary.Read(writer, binary.BigEndian, &length)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b = make([]byte, length)
|
||||||
|
n, err := io.ReadFull(writer, b)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != int(length) {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type PacketBundle interface {
|
||||||
|
Overhead() int
|
||||||
|
WriteToBundle(b []byte, writer io.Writer) (err error)
|
||||||
|
ReadFromBundle(writer io.Reader) (b []byte, err error)
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
package packetconn
|
||||||
|
|
||||||
|
//go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
|
429
transport/internet/request/assembler/packetconn/req2packet.go
Normal file
429
transport/internet/request/assembler/packetconn/req2packet.go
Normal file
@ -0,0 +1,429 @@
|
|||||||
|
package packetconn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang-collections/go-datastructures/queue"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/transport/internet/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newRequestToPacketConnClient(ctx context.Context, config *ClientConfig) (*requestToPacketConnClient, error) { //nolint: unparam
|
||||||
|
return &requestToPacketConnClient{ctx: ctx, config: config}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type requestToPacketConnClient struct {
|
||||||
|
assembly request.TransportClientAssembly
|
||||||
|
ctx context.Context
|
||||||
|
config *ClientConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnClient) OnTransportClientAssemblyReady(assembly request.TransportClientAssembly) {
|
||||||
|
r.assembly = assembly
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnClient) Dial() (io.ReadWriteCloser, error) {
|
||||||
|
sessionID := make([]byte, 16)
|
||||||
|
_, err := rand.Read(sessionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ctxWithCancel, cancel := context.WithCancel(r.ctx)
|
||||||
|
|
||||||
|
clientSess := &requestToPacketConnClientSession{
|
||||||
|
sessionID: sessionID,
|
||||||
|
currentPollingInterval: int(r.config.PollingIntervalInitial),
|
||||||
|
maxRequestSize: int(r.config.MaxRequestSize),
|
||||||
|
maxWriteDelay: int(r.config.MaxWriteDelay),
|
||||||
|
assembly: r.assembly,
|
||||||
|
writerChan: make(chan []byte, 256),
|
||||||
|
readerChan: make(chan []byte, 256),
|
||||||
|
ctx: ctxWithCancel,
|
||||||
|
finish: cancel,
|
||||||
|
}
|
||||||
|
go clientSess.keepRunning()
|
||||||
|
return clientSess, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type requestToPacketConnClientSession struct {
|
||||||
|
sessionID []byte
|
||||||
|
currentPollingInterval int
|
||||||
|
|
||||||
|
maxRequestSize int
|
||||||
|
maxWriteDelay int
|
||||||
|
|
||||||
|
assembly request.TransportClientAssembly
|
||||||
|
writerChan chan []byte
|
||||||
|
readerChan chan []byte
|
||||||
|
ctx context.Context
|
||||||
|
finish func()
|
||||||
|
nextWrite []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnClientSession) keepRunning() {
|
||||||
|
for r.ctx.Err() == nil {
|
||||||
|
r.runOnce()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnClientSession) runOnce() {
|
||||||
|
requestBody := bytes.NewBuffer(nil)
|
||||||
|
waitTimer := time.NewTimer(time.Duration(r.currentPollingInterval) * time.Millisecond)
|
||||||
|
var seenPacket bool
|
||||||
|
packetBundler := NewPacketBundle()
|
||||||
|
copyFromChan:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-r.ctx.Done():
|
||||||
|
return
|
||||||
|
case <-waitTimer.C:
|
||||||
|
break copyFromChan
|
||||||
|
case packet := <-r.writerChan:
|
||||||
|
if !seenPacket {
|
||||||
|
seenPacket = true
|
||||||
|
waitTimer.Stop()
|
||||||
|
waitTimer.Reset(time.Duration(r.maxWriteDelay) * time.Millisecond)
|
||||||
|
}
|
||||||
|
sizeOffset := packetBundler.Overhead() + len(packet)
|
||||||
|
if requestBody.Len()+sizeOffset > r.maxRequestSize {
|
||||||
|
r.nextWrite = packet
|
||||||
|
break copyFromChan
|
||||||
|
}
|
||||||
|
err := packetBundler.WriteToBundle(packet, requestBody)
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to write to bundle").Base(err).WriteToLog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
waitTimer.Stop()
|
||||||
|
go func() {
|
||||||
|
reader, writer := io.Pipe()
|
||||||
|
streamingRespOpt := &pipedStreamingRespOption{writer}
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
if packet, err := packetBundler.ReadFromBundle(reader); err == nil {
|
||||||
|
r.readerChan <- packet
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resp, err := r.assembly.Tripper().RoundTrip(r.ctx, request.Request{Data: requestBody.Bytes(), ConnectionTag: r.sessionID},
|
||||||
|
streamingRespOpt)
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to roundtrip").Base(err).WriteToLog()
|
||||||
|
if r.ctx.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp.Data != nil && len(resp.Data) != 0 {
|
||||||
|
respReader := bytes.NewReader(resp.Data)
|
||||||
|
for respReader.Len() != 0 {
|
||||||
|
packet, err := packetBundler.ReadFromBundle(respReader)
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to read from bundle").Base(err).WriteToLog()
|
||||||
|
if r.ctx.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.readerChan <- packet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
type pipedStreamingRespOption struct {
|
||||||
|
writer *io.PipeWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipedStreamingRespOption) RoundTripperOption() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipedStreamingRespOption) GetResponseWriter() io.Writer {
|
||||||
|
return p.writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnClientSession) Write(p []byte) (n int, err error) {
|
||||||
|
buf := make([]byte, len(p))
|
||||||
|
copy(buf, p)
|
||||||
|
select {
|
||||||
|
case <-r.ctx.Done():
|
||||||
|
return 0, r.ctx.Err()
|
||||||
|
case r.writerChan <- buf:
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnClientSession) Read(p []byte) (n int, err error) {
|
||||||
|
select {
|
||||||
|
case <-r.ctx.Done():
|
||||||
|
return 0, r.ctx.Err()
|
||||||
|
case buf := <-r.readerChan:
|
||||||
|
copy(p, buf)
|
||||||
|
return len(buf), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnClientSession) Close() error {
|
||||||
|
r.finish()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRequestToPacketConnServer(ctx context.Context, config *ServerConfig) *requestToPacketConnServer {
|
||||||
|
return &requestToPacketConnServer{
|
||||||
|
sessionMap: make(map[string]*requestToPacketConnServerSession),
|
||||||
|
ctx: ctx,
|
||||||
|
config: config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type requestToPacketConnServer struct {
|
||||||
|
packetSessionReceiver request.SessionReceiver
|
||||||
|
|
||||||
|
sessionMap map[string]*requestToPacketConnServerSession
|
||||||
|
|
||||||
|
ctx context.Context
|
||||||
|
config *ServerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnServer) onSessionReceiverReady(sessrecv request.SessionReceiver) {
|
||||||
|
r.packetSessionReceiver = sessrecv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnServer) OnRoundTrip(ctx context.Context, req request.Request,
|
||||||
|
opts ...request.RoundTripperOption,
|
||||||
|
) (resp request.Response, err error) {
|
||||||
|
SessionID := req.ConnectionTag
|
||||||
|
if SessionID == nil {
|
||||||
|
return request.Response{}, newError("nil session id")
|
||||||
|
}
|
||||||
|
sessionID := string(SessionID)
|
||||||
|
session, found := r.sessionMap[sessionID]
|
||||||
|
if !found {
|
||||||
|
ctxWithFinish, finish := context.WithCancel(ctx)
|
||||||
|
session = &requestToPacketConnServerSession{
|
||||||
|
SessionID: SessionID,
|
||||||
|
writingConnectionQueue: queue.New(64),
|
||||||
|
writerChan: make(chan []byte, int(r.config.PacketWritingBuffer)),
|
||||||
|
readerChan: make(chan []byte, 256),
|
||||||
|
ctx: ctxWithFinish,
|
||||||
|
finish: finish,
|
||||||
|
server: r,
|
||||||
|
maxWriteSize: int(r.config.MaxWriteSize),
|
||||||
|
maxWriteDuration: int(r.config.MaxWriteDurationMs),
|
||||||
|
maxSimultaneousWriteConnection: int(r.config.MaxSimultaneousWriteConnection),
|
||||||
|
}
|
||||||
|
r.sessionMap[sessionID] = session
|
||||||
|
err = r.packetSessionReceiver.OnNewSession(ctx, session)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return request.Response{}, err
|
||||||
|
}
|
||||||
|
return session.OnRoundTrip(ctx, req, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnServer) removeSessionID(sessionID []byte) {
|
||||||
|
delete(r.sessionMap, string(sessionID))
|
||||||
|
}
|
||||||
|
|
||||||
|
type requestToPacketConnServerSession struct {
|
||||||
|
SessionID []byte
|
||||||
|
|
||||||
|
writingConnectionQueue *queue.Queue
|
||||||
|
|
||||||
|
writerChan chan []byte
|
||||||
|
readerChan chan []byte
|
||||||
|
ctx context.Context
|
||||||
|
finish func()
|
||||||
|
server *requestToPacketConnServer
|
||||||
|
|
||||||
|
maxWriteSize int
|
||||||
|
maxWriteDuration int
|
||||||
|
maxSimultaneousWriteConnection int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnServerSession) Read(p []byte) (n int, err error) {
|
||||||
|
select {
|
||||||
|
case <-r.ctx.Done():
|
||||||
|
return 0, r.ctx.Err()
|
||||||
|
case buf := <-r.readerChan:
|
||||||
|
copy(p, buf)
|
||||||
|
return len(buf), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var debugStats struct {
|
||||||
|
packetWritten int
|
||||||
|
packetDropped int
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
var _ = func() bool {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
newError("packet written: ", debugStats.packetWritten, " packet dropped: ", debugStats.packetDropped).WriteToLog()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return true
|
||||||
|
}()*/
|
||||||
|
|
||||||
|
func (r *requestToPacketConnServerSession) Write(p []byte) (n int, err error) {
|
||||||
|
buf := make([]byte, len(p))
|
||||||
|
copy(buf, p)
|
||||||
|
select {
|
||||||
|
case <-r.ctx.Done():
|
||||||
|
return 0, r.ctx.Err()
|
||||||
|
case r.writerChan <- buf:
|
||||||
|
debugStats.packetWritten++
|
||||||
|
return len(p), nil
|
||||||
|
default: // This write will be called from global listener's routine, it must not block
|
||||||
|
debugStats.packetDropped++
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnServerSession) Close() error {
|
||||||
|
r.server.removeSessionID(r.SessionID)
|
||||||
|
r.finish()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type writingConnection struct {
|
||||||
|
focus func()
|
||||||
|
finish func()
|
||||||
|
finishCtx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestToPacketConnServerSession) OnRoundTrip(ctx context.Context, req request.Request,
|
||||||
|
opts ...request.RoundTripperOption,
|
||||||
|
) (resp request.Response, err error) {
|
||||||
|
// TODO: fix connection graceful close
|
||||||
|
var streamingRespWriter io.Writer
|
||||||
|
var streamingRespWriterFlusher request.OptionSupportsStreamingResponseExtensionFlusher
|
||||||
|
for _, opt := range opts {
|
||||||
|
if streamingRespOpt, ok := opt.(request.OptionSupportsStreamingResponse); ok {
|
||||||
|
streamingRespWriter = streamingRespOpt.GetResponseWriter()
|
||||||
|
if streamingRespWriterFlusherOpt, ok := opt.(request.OptionSupportsStreamingResponseExtensionFlusher); ok {
|
||||||
|
streamingRespWriterFlusher = streamingRespWriterFlusherOpt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
packetBundler := NewPacketBundle()
|
||||||
|
reqReader := bytes.NewReader(req.Data)
|
||||||
|
for reqReader.Len() != 0 {
|
||||||
|
packet, err := packetBundler.ReadFromBundle(reqReader)
|
||||||
|
if err != nil {
|
||||||
|
err = newError("failed to read from bundle").Base(err)
|
||||||
|
return request.Response{}, err
|
||||||
|
}
|
||||||
|
r.readerChan <- packet
|
||||||
|
}
|
||||||
|
onFocusCtx, focus := context.WithCancel(ctx)
|
||||||
|
onFinishCtx, finish := context.WithCancel(ctx)
|
||||||
|
r.writingConnectionQueue.Put(&writingConnection{
|
||||||
|
focus: focus,
|
||||||
|
finish: finish,
|
||||||
|
finishCtx: onFinishCtx,
|
||||||
|
})
|
||||||
|
|
||||||
|
amountToEnd := r.writingConnectionQueue.Len() - int64(r.maxSimultaneousWriteConnection)
|
||||||
|
for amountToEnd > 0 {
|
||||||
|
{
|
||||||
|
_, _ = r.writingConnectionQueue.TakeUntil(func(i interface{}) bool {
|
||||||
|
i.(*writingConnection).finish()
|
||||||
|
amountToEnd--
|
||||||
|
return amountToEnd > 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
_, _ = r.writingConnectionQueue.TakeUntil(func(i interface{}) bool {
|
||||||
|
i.(*writingConnection).focus()
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferedRespWriter := bytes.NewBuffer(nil)
|
||||||
|
finishWrite := func() {
|
||||||
|
resp.Data = bufferedRespWriter.Bytes()
|
||||||
|
{
|
||||||
|
_, _ = r.writingConnectionQueue.TakeUntil(func(i interface{}) bool {
|
||||||
|
i.(*writingConnection).focus()
|
||||||
|
if i.(*writingConnection).finishCtx.Err() != nil { //nolint: gosimple
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
progressiveSend := streamingRespWriter != nil
|
||||||
|
var respWriter io.Writer
|
||||||
|
if progressiveSend {
|
||||||
|
respWriter = streamingRespWriter
|
||||||
|
} else {
|
||||||
|
respWriter = bufferedRespWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytesSent int
|
||||||
|
onReceivePacket := func(packet []byte) bool {
|
||||||
|
bytesSent += len(packet) + packetBundler.Overhead()
|
||||||
|
err := packetBundler.WriteToBundle(packet, respWriter)
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to write to bundle").Base(err).WriteToLog()
|
||||||
|
}
|
||||||
|
if streamingRespWriterFlusher != nil {
|
||||||
|
streamingRespWriterFlusher.Flush()
|
||||||
|
}
|
||||||
|
if bytesSent >= r.maxWriteSize {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
finishWriteTimer := time.NewTimer(time.Millisecond * time.Duration(r.maxWriteDuration))
|
||||||
|
|
||||||
|
if !progressiveSend {
|
||||||
|
select {
|
||||||
|
case <-onFocusCtx.Done():
|
||||||
|
case <-onFinishCtx.Done():
|
||||||
|
finishWrite()
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
select {
|
||||||
|
case <-onFinishCtx.Done():
|
||||||
|
finishWrite()
|
||||||
|
return resp, nil
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
firstRead := true
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-onFinishCtx.Done():
|
||||||
|
finishWrite()
|
||||||
|
finishWriteTimer.Stop()
|
||||||
|
return resp, nil
|
||||||
|
case packet := <-r.writerChan:
|
||||||
|
keepSending := onReceivePacket(packet)
|
||||||
|
if firstRead {
|
||||||
|
firstRead = false
|
||||||
|
}
|
||||||
|
if !keepSending {
|
||||||
|
finishWrite()
|
||||||
|
finishWriteTimer.Stop()
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
case <-finishWriteTimer.C:
|
||||||
|
finishWrite()
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package packetconn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/net"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/serial"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/transport/internet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wrappedTransportEnvironment struct {
|
||||||
|
environment.TransportEnvironment
|
||||||
|
client *requestToPacketConnClient
|
||||||
|
server *requestToPacketConnServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedTransportEnvironment) Listen(ctx context.Context, addr net.Addr, sockopt *internet.SocketConfig) (net.Listener, error) {
|
||||||
|
return nil, newError("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedTransportEnvironment) ListenPacket(ctx context.Context, addr net.Addr, sockopt *internet.SocketConfig) (net.PacketConn, error) {
|
||||||
|
packetConn := newWrappedPacketConn(ctx)
|
||||||
|
w.server.onSessionReceiverReady(packetConn)
|
||||||
|
return packetConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedTransportEnvironment) Dial(ctx context.Context, source net.Address, destination net.Destination, sockopt *internet.SocketConfig) (net.Conn, error) {
|
||||||
|
session, err := w.client.Dial()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newWrappedConn(session), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedTransportEnvironment) Dialer() internet.SystemDialer {
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedTransportEnvironment) Listener() internet.SystemListener {
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUDPAssemblerServerFromConfig(ctx context.Context, config *ServerConfig) (*udpAssemblerServer, error) {
|
||||||
|
instance, err := serial.GetInstanceOf(config.UnderlyingTransportSetting)
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("failed to get instance of underlying transport").Base(err).AtError()
|
||||||
|
}
|
||||||
|
memcfg := &internet.MemoryStreamConfig{ProtocolName: config.UnderlyingTransportName, ProtocolSettings: instance}
|
||||||
|
return newUDPAssemblerServer(ctx, config, memcfg), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUDPAssemblerClientFromConfig(ctx context.Context, config *ClientConfig) (*udpAssemblerClient, error) {
|
||||||
|
instance, err := serial.GetInstanceOf(config.UnderlyingTransportSetting)
|
||||||
|
if err != nil {
|
||||||
|
return nil, newError("failed to get instance of underlying transport").Base(err).AtError()
|
||||||
|
}
|
||||||
|
memcfg := &internet.MemoryStreamConfig{ProtocolName: config.UnderlyingTransportName, ProtocolSettings: instance}
|
||||||
|
return newUDPAssemblerClient(ctx, config, memcfg), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
|
serverConfig, ok := config.(*ServerConfig)
|
||||||
|
if !ok {
|
||||||
|
return nil, newError("not a ServerConfig")
|
||||||
|
}
|
||||||
|
return newUDPAssemblerServerFromConfig(ctx, serverConfig)
|
||||||
|
}))
|
||||||
|
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
|
clientConfig, ok := config.(*ClientConfig)
|
||||||
|
if !ok {
|
||||||
|
return nil, newError("not a ClientConfig")
|
||||||
|
}
|
||||||
|
return newUDPAssemblerClientFromConfig(ctx, clientConfig)
|
||||||
|
}))
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package packetconn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
gonet "net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/net"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/transport/internet"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/transport/internet/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
type udpAssemblerClient struct {
|
||||||
|
ctx context.Context
|
||||||
|
streamSettings *internet.MemoryStreamConfig
|
||||||
|
assembly request.TransportClientAssembly
|
||||||
|
req2connc *requestToPacketConnClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *udpAssemblerClient) NewSession(ctx context.Context, opts ...request.SessionOption) (request.Session, error) {
|
||||||
|
return u.dial(net.Destination{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *udpAssemblerClient) OnTransportClientAssemblyReady(assembly request.TransportClientAssembly) {
|
||||||
|
u.assembly = assembly
|
||||||
|
u.req2connc.OnTransportClientAssemblyReady(assembly)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWrappedConn(in io.ReadWriteCloser) net.Conn {
|
||||||
|
return wrappedConn{in}
|
||||||
|
}
|
||||||
|
|
||||||
|
type wrappedConn struct {
|
||||||
|
io.ReadWriteCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w wrappedConn) LocalAddr() gonet.Addr {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w wrappedConn) RemoteAddr() gonet.Addr {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w wrappedConn) SetDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w wrappedConn) SetReadDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w wrappedConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWrappedPacketConn(ctx context.Context) *wrappedPacketConn {
|
||||||
|
ctxWithCancel, cancel := context.WithCancel(ctx)
|
||||||
|
return &wrappedPacketConn{
|
||||||
|
conn: make(map[string]*serverSession),
|
||||||
|
readChan: make(chan packet, 16), ctx: ctxWithCancel, finish: cancel, connLock: &sync.Mutex{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUDPAssemblerClient(ctx context.Context, config *ClientConfig, streamSettings *internet.MemoryStreamConfig) *udpAssemblerClient {
|
||||||
|
transportEnvironment := envctx.EnvironmentFromContext(ctx).(environment.TransportEnvironment)
|
||||||
|
transportEnvironmentWrapped := &wrappedTransportEnvironment{TransportEnvironment: transportEnvironment}
|
||||||
|
transportEnvironmentWrapped.client, _ = newRequestToPacketConnClient(ctx, config)
|
||||||
|
wrappedContext := envctx.ContextWithEnvironment(ctx, transportEnvironmentWrapped)
|
||||||
|
return &udpAssemblerClient{ctx: wrappedContext, streamSettings: streamSettings, req2connc: transportEnvironmentWrapped.client}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *udpAssemblerClient) dial(dest net.Destination) (internet.Connection, error) {
|
||||||
|
_ = dest
|
||||||
|
return internet.Dial(u.ctx, net.TCPDestination(net.LocalHostIP, 0), u.streamSettings)
|
||||||
|
}
|
@ -0,0 +1,166 @@
|
|||||||
|
package packetconn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
||||||
|
net2 "github.com/v2fly/v2ray-core/v5/common/net"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/transport/internet"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/transport/internet/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
type packet struct {
|
||||||
|
addr string
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type wrappedPacketConn struct {
|
||||||
|
connLock *sync.Mutex
|
||||||
|
conn map[string]*serverSession
|
||||||
|
|
||||||
|
readChan chan packet
|
||||||
|
|
||||||
|
ctx context.Context
|
||||||
|
finish func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||||
|
select {
|
||||||
|
case pack := <-w.readChan:
|
||||||
|
n := copy(p, pack.data)
|
||||||
|
if n < len(pack.data) {
|
||||||
|
return n, nil, io.ErrShortBuffer
|
||||||
|
}
|
||||||
|
return n, &net.UDPAddr{IP: net2.IP(pack.addr)}, nil
|
||||||
|
case <-w.ctx.Done():
|
||||||
|
return 0, nil, w.ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||||
|
w.connLock.Lock()
|
||||||
|
conn := w.conn[string(addr.(*net.UDPAddr).IP)]
|
||||||
|
w.connLock.Unlock()
|
||||||
|
return conn.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedPacketConn) Close() error {
|
||||||
|
w.finish()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedPacketConn) LocalAddr() net.Addr {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedPacketConn) SetDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedPacketConn) SetReadDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedPacketConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w wrappedPacketConn) OnNewSession(ctx context.Context, sess request.Session, opts ...request.SessionOption) error {
|
||||||
|
imaginaryAddr := net2.UDPAddr{
|
||||||
|
IP: net2.AnyIPv6.IP(),
|
||||||
|
Port: 0,
|
||||||
|
}
|
||||||
|
rand.Read([]byte(imaginaryAddr.IP))
|
||||||
|
session := newServerSession(ctx, sess, string(imaginaryAddr.IP), &w)
|
||||||
|
w.connLock.Lock()
|
||||||
|
w.conn[string(imaginaryAddr.IP)] = session
|
||||||
|
w.connLock.Unlock()
|
||||||
|
session.start()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newServerSession(ctx context.Context, sess request.Session, name string, listener *wrappedPacketConn) *serverSession {
|
||||||
|
_ = ctx
|
||||||
|
return &serverSession{session: sess, name: name, listener: listener}
|
||||||
|
}
|
||||||
|
|
||||||
|
type serverSession struct {
|
||||||
|
name string
|
||||||
|
session request.Session
|
||||||
|
listener *wrappedPacketConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *serverSession) start() {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-s.listener.ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
buf := make([]byte, 2000)
|
||||||
|
n, err := s.session.Read(buf)
|
||||||
|
if err != nil || n > 2000 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.listener.readChan <- packet{s.name, buf[:n]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *serverSession) Write(p []byte) (int, error) {
|
||||||
|
return s.session.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
type udpAssemblerServer struct {
|
||||||
|
ctx context.Context
|
||||||
|
streamSettings *internet.MemoryStreamConfig
|
||||||
|
assembly request.TransportServerAssembly
|
||||||
|
req2packs *requestToPacketConnServer
|
||||||
|
listener internet.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *udpAssemblerServer) Start() error {
|
||||||
|
listener, err := u.listen(net2.LocalHostIP, 0)
|
||||||
|
if err != nil {
|
||||||
|
return newError("failed to listen").Base(err).AtError()
|
||||||
|
}
|
||||||
|
u.listener = listener
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *udpAssemblerServer) Close() error {
|
||||||
|
return u.listener.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *udpAssemblerServer) OnRoundTrip(ctx context.Context, req request.Request, opts ...request.RoundTripperOption) (resp request.Response, err error) {
|
||||||
|
return u.req2packs.OnRoundTrip(ctx, req, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *udpAssemblerServer) OnTransportServerAssemblyReady(assembly request.TransportServerAssembly) {
|
||||||
|
u.assembly = assembly
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUDPAssemblerServer(ctx context.Context, config *ServerConfig, streamSettings *internet.MemoryStreamConfig) *udpAssemblerServer {
|
||||||
|
transportEnvironment := envctx.EnvironmentFromContext(ctx).(environment.TransportEnvironment)
|
||||||
|
transportEnvironmentWrapped := &wrappedTransportEnvironment{TransportEnvironment: transportEnvironment}
|
||||||
|
transportEnvironmentWrapped.server = newRequestToPacketConnServer(ctx, config)
|
||||||
|
wrappedContext := envctx.ContextWithEnvironment(ctx, transportEnvironmentWrapped)
|
||||||
|
return &udpAssemblerServer{ctx: wrappedContext, streamSettings: streamSettings, req2packs: transportEnvironmentWrapped.server}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *udpAssemblerServer) listen(address net2.Address, port net2.Port) (internet.Listener, error) {
|
||||||
|
return internet.ListenTCP(u.ctx, address, port, u.streamSettings, func(connection internet.Connection) {
|
||||||
|
err := u.assembly.SessionReceiver().OnNewSession(u.ctx, connection)
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to handle new session").Base(err).WriteToLog()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -36,6 +36,11 @@ func (s server) Close() error {
|
|||||||
if err := s.tripper.Close(); err != nil {
|
if err := s.tripper.Close(); err != nil {
|
||||||
return newError("failed to close tripper").Base(err)
|
return newError("failed to close tripper").Base(err)
|
||||||
}
|
}
|
||||||
|
if runnableAssembler, ok := s.assembler.(common.Runnable); ok {
|
||||||
|
if err := runnableAssembler.Close(); err != nil {
|
||||||
|
return newError("failed to close assembler").Base(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +132,12 @@ func listenRequest(ctx context.Context, address net.Address, port net.Port, stre
|
|||||||
return nil, newError("failed to start tripper").Base(err)
|
return nil, newError("failed to start tripper").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if runnableAssembler, ok := serverAssembly.assembler.(common.Runnable); ok {
|
||||||
|
if err := runnableAssembler.Start(); err != nil {
|
||||||
|
return nil, newError("failed to start assembler").Base(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return serverAssembly, nil
|
return serverAssembly, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package request
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v5/common"
|
"github.com/v2fly/v2ray-core/v5/common"
|
||||||
)
|
)
|
||||||
@ -36,3 +37,12 @@ type Request struct {
|
|||||||
type Response struct {
|
type Response struct {
|
||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OptionSupportsStreamingResponse interface {
|
||||||
|
RoundTripperOption
|
||||||
|
GetResponseWriter() io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
type OptionSupportsStreamingResponseExtensionFlusher interface {
|
||||||
|
Flush()
|
||||||
|
}
|
||||||
|
@ -20,7 +20,9 @@ type ClientConfig struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Http *HTTPConfig `protobuf:"bytes,1,opt,name=http,proto3" json:"http,omitempty"`
|
Http *HTTPConfig `protobuf:"bytes,1,opt,name=http,proto3" json:"http,omitempty"`
|
||||||
|
AllowHttp bool `protobuf:"varint,2,opt,name=allow_http,json=allowHttp,proto3" json:"allow_http,omitempty"`
|
||||||
|
H2PoolSize int32 `protobuf:"varint,3,opt,name=h2_pool_size,json=h2PoolSize,proto3" json:"h2_pool_size,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ClientConfig) Reset() {
|
func (x *ClientConfig) Reset() {
|
||||||
@ -62,6 +64,20 @@ func (x *ClientConfig) GetHttp() *HTTPConfig {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *ClientConfig) GetAllowHttp() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.AllowHttp
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ClientConfig) GetH2PoolSize() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.H2PoolSize
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@ -184,48 +200,52 @@ var file_transport_internet_request_roundtripper_httprt_config_proto_rawDesc = [
|
|||||||
0x75, 0x65, 0x73, 0x74, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65,
|
0x75, 0x65, 0x73, 0x74, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65,
|
||||||
0x72, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x72, 0x74, 0x1a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
0x72, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x72, 0x74, 0x1a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78, 0x74, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
|
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, 0x9e, 0x01, 0x0a, 0x0c, 0x43,
|
0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdf, 0x01, 0x0a, 0x0c, 0x43,
|
||||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a, 0x04, 0x68,
|
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a, 0x04, 0x68,
|
||||||
0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x76, 0x32, 0x72, 0x61,
|
0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x76, 0x32, 0x72, 0x61,
|
||||||
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
|
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
|
||||||
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
0x74, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x68,
|
0x74, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x68,
|
||||||
0x74, 0x74, 0x70, 0x72, 0x74, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x74, 0x74, 0x70, 0x72, 0x74, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x33, 0x82, 0xb5, 0x18, 0x2f, 0x0a, 0x25, 0x74, 0x72,
|
0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f,
|
||||||
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e,
|
0x68, 0x74, 0x74, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x6c, 0x6c, 0x6f,
|
||||||
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x63, 0x6c, 0x69,
|
0x77, 0x48, 0x74, 0x74, 0x70, 0x12, 0x20, 0x0a, 0x0c, 0x68, 0x32, 0x5f, 0x70, 0x6f, 0x6f, 0x6c,
|
||||||
0x65, 0x6e, 0x74, 0x12, 0x06, 0x68, 0x74, 0x74, 0x70, 0x72, 0x74, 0x22, 0xd5, 0x01, 0x0a, 0x0c,
|
0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x68, 0x32, 0x50,
|
||||||
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a, 0x04,
|
0x6f, 0x6f, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x3a, 0x33, 0x82, 0xb5, 0x18, 0x2f, 0x0a, 0x25, 0x74,
|
||||||
0x68, 0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x76, 0x32, 0x72,
|
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
|
0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x63, 0x6c,
|
||||||
|
0x69, 0x65, 0x6e, 0x74, 0x12, 0x06, 0x68, 0x74, 0x74, 0x70, 0x72, 0x74, 0x22, 0xd5, 0x01, 0x0a,
|
||||||
|
0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a,
|
||||||
|
0x04, 0x68, 0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x76, 0x32,
|
||||||
|
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
|
||||||
|
0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x71, 0x75,
|
||||||
|
0x65, 0x73, 0x74, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72,
|
||||||
|
0x2e, 0x68, 0x74, 0x74, 0x70, 0x72, 0x74, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x43, 0x6f, 0x6e, 0x66,
|
||||||
|
0x69, 0x67, 0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x12, 0x35, 0x0a, 0x17, 0x6e, 0x6f, 0x5f, 0x64,
|
||||||
|
0x65, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
|
||||||
|
0x74, 0x61, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x6e, 0x6f, 0x44, 0x65, 0x63,
|
||||||
|
0x6f, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x67, 0x3a,
|
||||||
|
0x33, 0x82, 0xb5, 0x18, 0x2f, 0x0a, 0x25, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
|
||||||
|
0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72,
|
||||||
|
0x69, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x06, 0x68, 0x74,
|
||||||
|
0x74, 0x70, 0x72, 0x74, 0x22, 0x3e, 0x0a, 0x0a, 0x48, 0x54, 0x54, 0x50, 0x43, 0x6f, 0x6e, 0x66,
|
||||||
|
0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||||
|
0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x72, 0x6c, 0x50, 0x72, 0x65,
|
||||||
|
0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x72, 0x6c, 0x50, 0x72,
|
||||||
|
0x65, 0x66, 0x69, 0x78, 0x42, 0xcc, 0x01, 0x0a, 0x3d, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72,
|
||||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
||||||
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65,
|
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65,
|
||||||
0x73, 0x74, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72, 0x2e,
|
0x73, 0x74, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72, 0x2e,
|
||||||
0x68, 0x74, 0x74, 0x70, 0x72, 0x74, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
0x68, 0x74, 0x74, 0x70, 0x72, 0x74, 0x50, 0x01, 0x5a, 0x4d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||||
0x67, 0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x12, 0x35, 0x0a, 0x17, 0x6e, 0x6f, 0x5f, 0x64, 0x65,
|
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79,
|
||||||
0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74,
|
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x35, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
|
||||||
0x61, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x6e, 0x6f, 0x44, 0x65, 0x63, 0x6f,
|
0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x65, 0x71, 0x75,
|
||||||
0x64, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x67, 0x3a, 0x33,
|
0x65, 0x73, 0x74, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72,
|
||||||
0x82, 0xb5, 0x18, 0x2f, 0x0a, 0x25, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
|
0x2f, 0x68, 0x74, 0x74, 0x70, 0x72, 0x74, 0xaa, 0x02, 0x39, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,
|
||||||
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69,
|
0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49,
|
||||||
0x70, 0x70, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x06, 0x68, 0x74, 0x74,
|
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e,
|
||||||
0x70, 0x72, 0x74, 0x22, 0x3e, 0x0a, 0x0a, 0x48, 0x54, 0x54, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
0x52, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x74,
|
||||||
0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x70, 0x72, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x72, 0x6c, 0x50, 0x72, 0x65, 0x66,
|
|
||||||
0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x72, 0x6c, 0x50, 0x72, 0x65,
|
|
||||||
0x66, 0x69, 0x78, 0x42, 0xcc, 0x01, 0x0a, 0x3d, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61,
|
|
||||||
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
|
|
||||||
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
|
|
||||||
0x74, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x68,
|
|
||||||
0x74, 0x74, 0x70, 0x72, 0x74, 0x50, 0x01, 0x5a, 0x4d, 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, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
|
||||||
0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65,
|
|
||||||
0x73, 0x74, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72, 0x2f,
|
|
||||||
0x68, 0x74, 0x74, 0x70, 0x72, 0x74, 0xaa, 0x02, 0x39, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43,
|
|
||||||
0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e,
|
|
||||||
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x52,
|
|
||||||
0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x74, 0x70,
|
|
||||||
0x72, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -13,6 +13,8 @@ message ClientConfig {
|
|||||||
option (v2ray.core.common.protoext.message_opt).short_name = "httprt";
|
option (v2ray.core.common.protoext.message_opt).short_name = "httprt";
|
||||||
|
|
||||||
HTTPConfig http = 1;
|
HTTPConfig http = 1;
|
||||||
|
bool allow_http = 2;
|
||||||
|
int32 h2_pool_size = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ServerConfig {
|
message ServerConfig {
|
||||||
|
@ -40,31 +40,55 @@ func (h *httpTripperClient) OnTransportClientAssemblyReady(assembly request.Tran
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpTripperClient) RoundTrip(ctx context.Context, req request.Request, opts ...request.RoundTripperOption) (resp request.Response, err error) {
|
func (h *httpTripperClient) RoundTrip(ctx context.Context, req request.Request, opts ...request.RoundTripperOption) (resp request.Response, err error) {
|
||||||
|
var streamingWriter io.Writer
|
||||||
|
for _, v := range opts {
|
||||||
|
if streamingResp, ok := v.(request.OptionSupportsStreamingResponse); ok {
|
||||||
|
streamingWriter = streamingResp.GetResponseWriter()
|
||||||
|
}
|
||||||
|
}
|
||||||
if h.httpRTT == nil {
|
if h.httpRTT == nil {
|
||||||
h.httpRTT = transportcommon.NewALPNAwareHTTPRoundTripper(ctx, func(ctx context.Context, addr string) (gonet.Conn, error) {
|
var backDrop http.RoundTripper = unimplementedBackDrop{}
|
||||||
|
if h.config.AllowHttp {
|
||||||
|
backDrop = &http.Transport{
|
||||||
|
DialContext: func(_ context.Context, network, addr string) (gonet.Conn, error) {
|
||||||
|
return h.assembly.AutoImplDialer().Dial(ctx)
|
||||||
|
},
|
||||||
|
DialTLSContext: func(_ context.Context, network, addr string) (gonet.Conn, error) {
|
||||||
|
return nil, newError("unexpected dial of TLS")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.httpRTT = transportcommon.NewALPNAwareHTTPRoundTripperWithH2Pool(ctx, func(ctx context.Context, addr string) (gonet.Conn, error) {
|
||||||
return h.assembly.AutoImplDialer().Dial(ctx)
|
return h.assembly.AutoImplDialer().Dial(ctx)
|
||||||
}, unimplementedBackDrop{})
|
}, backDrop, int(h.config.H2PoolSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionTagStr := base64.RawURLEncoding.EncodeToString(req.ConnectionTag)
|
connectionTagStr := base64.RawURLEncoding.EncodeToString(req.ConnectionTag)
|
||||||
|
|
||||||
httpRequest, err := http.NewRequest("POST", h.config.Http.UrlPrefix+h.config.Http.Path, bytes.NewReader(req.Data))
|
httpRequest, err := http.NewRequest("POST", h.config.Http.UrlPrefix+h.config.Http.Path, bytes.NewReader(req.Data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
httpRequest.Header.Set("X-Session-ID", connectionTagStr)
|
httpRequest.Header.Set("X-Session-ID", connectionTagStr)
|
||||||
|
|
||||||
httpResp, err := h.httpRTT.RoundTrip(httpRequest)
|
httpResp, err := h.httpRTT.RoundTrip(httpRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return resp, err
|
||||||
}
|
}
|
||||||
defer httpResp.Body.Close()
|
defer httpResp.Body.Close()
|
||||||
result, err := io.ReadAll(httpResp.Body)
|
if streamingWriter == nil {
|
||||||
if err != nil {
|
result, err := io.ReadAll(httpResp.Body)
|
||||||
return
|
if err != nil {
|
||||||
|
return request.Response{}, err
|
||||||
|
}
|
||||||
|
return request.Response{Data: result}, err
|
||||||
}
|
}
|
||||||
return request.Response{Data: result}, err
|
_, err = io.Copy(streamingWriter, httpResp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return request.Response{}, newError("unable to copy response").Base(err)
|
||||||
|
}
|
||||||
|
return request.Response{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHTTPRoundTripperServer(ctx context.Context, config *ServerConfig) request.RoundTripperServer {
|
func newHTTPRoundTripperServer(ctx context.Context, config *ServerConfig) request.RoundTripperServer {
|
||||||
@ -87,6 +111,25 @@ func (h *httpTripperServer) ServeHTTP(writer http.ResponseWriter, r *http.Reques
|
|||||||
h.onRequest(writer, r)
|
h.onRequest(writer, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type httpRespStreamWriting struct {
|
||||||
|
resp http.ResponseWriter
|
||||||
|
used bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpRespStreamWriting) RoundTripperOption() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpRespStreamWriting) GetResponseWriter() io.Writer {
|
||||||
|
h.used = true
|
||||||
|
return h.resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpRespStreamWriting) Flush() {
|
||||||
|
if f, ok := h.resp.(http.Flusher); ok {
|
||||||
|
f.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (h *httpTripperServer) onRequest(resp http.ResponseWriter, req *http.Request) {
|
func (h *httpTripperServer) onRequest(resp http.ResponseWriter, req *http.Request) {
|
||||||
tail := req.Header.Get("X-Session-ID")
|
tail := req.Header.Get("X-Session-ID")
|
||||||
data := []byte(tail)
|
data := []byte(tail)
|
||||||
@ -103,10 +146,16 @@ func (h *httpTripperServer) onRequest(resp http.ResponseWriter, req *http.Reques
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
newError("unable to read body").Base(err).AtInfo().WriteToLog()
|
newError("unable to read body").Base(err).AtInfo().WriteToLog()
|
||||||
}
|
}
|
||||||
recvResp, err := h.assembly.TripperReceiver().OnRoundTrip(h.ctx, request.Request{Data: body, ConnectionTag: data})
|
|
||||||
|
streamingRespOption := &httpRespStreamWriting{resp: resp}
|
||||||
|
recvResp, err := h.assembly.TripperReceiver().OnRoundTrip(h.ctx, request.Request{Data: body, ConnectionTag: data},
|
||||||
|
streamingRespOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
newError("unable to process roundtrip").Base(err).AtInfo().WriteToLog()
|
newError("unable to process roundtrip").Base(err).AtInfo().WriteToLog()
|
||||||
}
|
}
|
||||||
|
if streamingRespOption.used {
|
||||||
|
return
|
||||||
|
}
|
||||||
_, err = io.Copy(resp, bytes.NewReader(recvResp.Data))
|
_, err = io.Copy(resp, bytes.NewReader(recvResp.Data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
newError("unable to send response").Base(err).AtInfo().WriteToLog()
|
newError("unable to send response").Base(err).AtInfo().WriteToLog()
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -194,6 +195,16 @@ func (c *Config) verifyPeerCert(rawCerts [][]byte, verifiedChains [][]*x509.Cert
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type alwaysFlushWriter struct {
|
||||||
|
file *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *alwaysFlushWriter) Write(p []byte) (n int, err error) {
|
||||||
|
n, err = a.file.Write(p)
|
||||||
|
a.file.Sync()
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetTLSConfig converts this Config into tls.Config.
|
// GetTLSConfig converts this Config into tls.Config.
|
||||||
func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
|
func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
|
||||||
root, err := c.getCertPool()
|
root, err := c.getCertPool()
|
||||||
|
@ -17,10 +17,17 @@ import (
|
|||||||
|
|
||||||
type DialerFunc func(ctx context.Context, addr string) (net.Conn, error)
|
type DialerFunc func(ctx context.Context, addr string) (net.Conn, error)
|
||||||
|
|
||||||
// NewALPNAwareHTTPRoundTripper creates an instance of RoundTripper that dial to remote HTTPS endpoint with
|
|
||||||
// an alternative version of TLS implementation.
|
|
||||||
func NewALPNAwareHTTPRoundTripper(ctx context.Context, dialer DialerFunc,
|
func NewALPNAwareHTTPRoundTripper(ctx context.Context, dialer DialerFunc,
|
||||||
backdropTransport http.RoundTripper,
|
backdropTransport http.RoundTripper,
|
||||||
|
) http.RoundTripper {
|
||||||
|
return NewALPNAwareHTTPRoundTripperWithH2Pool(ctx, dialer, backdropTransport, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewALPNAwareHTTPRoundTripperWithH2Pool creates an instance of RoundTripper that dial to remote HTTPS endpoint with
|
||||||
|
// an alternative version of TLS implementation.
|
||||||
|
func NewALPNAwareHTTPRoundTripperWithH2Pool(ctx context.Context, dialer DialerFunc,
|
||||||
|
backdropTransport http.RoundTripper,
|
||||||
|
h2PoolSize int,
|
||||||
) http.RoundTripper {
|
) http.RoundTripper {
|
||||||
rtImpl := &alpnAwareHTTPRoundTripperImpl{
|
rtImpl := &alpnAwareHTTPRoundTripperImpl{
|
||||||
connectWithH1: map[string]bool{},
|
connectWithH1: map[string]bool{},
|
||||||
@ -46,6 +53,8 @@ type alpnAwareHTTPRoundTripperImpl struct {
|
|||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
dialer DialerFunc
|
dialer DialerFunc
|
||||||
|
|
||||||
|
h2PoolSize int
|
||||||
}
|
}
|
||||||
|
|
||||||
type pendingConnKey struct {
|
type pendingConnKey struct {
|
||||||
@ -175,10 +184,20 @@ func (r *alpnAwareHTTPRoundTripperImpl) dialTLS(ctx context.Context, addr string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *alpnAwareHTTPRoundTripperImpl) init() {
|
func (r *alpnAwareHTTPRoundTripperImpl) init() {
|
||||||
r.httpsH2Transport = &http2.Transport{
|
if r.h2PoolSize >= 2 {
|
||||||
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
r.httpsH2Transport = newH2TransportPool(int64(r.h2PoolSize), func() *http2.Transport {
|
||||||
return r.dialOrGetTLSWithExpectedALPN(context.Background(), addr, true)
|
return &http2.Transport{
|
||||||
},
|
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||||
|
return r.dialOrGetTLSWithExpectedALPN(context.Background(), addr, true)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
r.httpsH2Transport = &http2.Transport{
|
||||||
|
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||||
|
return r.dialOrGetTLSWithExpectedALPN(context.Background(), addr, true)
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
r.httpsH1Transport = &http.Transport{
|
r.httpsH1Transport = &http.Transport{
|
||||||
DialTLSContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
|
DialTLSContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
|
||||||
@ -220,3 +239,29 @@ func (c *unclaimedConnection) tick() {
|
|||||||
c.Conn = nil
|
c.Conn = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type h2TransportFactory func() *http2.Transport
|
||||||
|
|
||||||
|
func newH2TransportPool(size int64, h2factory h2TransportFactory) *h2TransportPool {
|
||||||
|
return &h2TransportPool{
|
||||||
|
pool: make([]*http2.Transport, size),
|
||||||
|
size: size,
|
||||||
|
h2factory: h2factory,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type h2TransportPool struct {
|
||||||
|
pool []*http2.Transport
|
||||||
|
h2factory h2TransportFactory
|
||||||
|
usageCount int64
|
||||||
|
size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *h2TransportPool) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||||
|
currentSlot := h.usageCount % h.size
|
||||||
|
h.usageCount++
|
||||||
|
if h.pool[currentSlot] == nil {
|
||||||
|
h.pool[currentSlot] = h.h2factory()
|
||||||
|
}
|
||||||
|
return h.pool[currentSlot].RoundTrip(request)
|
||||||
|
}
|
||||||
|
@ -3,6 +3,9 @@ package udp
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v5/common/buf"
|
"github.com/v2fly/v2ray-core/v5/common/buf"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/net"
|
"github.com/v2fly/v2ray-core/v5/common/net"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/protocol/udp"
|
"github.com/v2fly/v2ray-core/v5/common/protocol/udp"
|
||||||
@ -25,6 +28,7 @@ func HubReceiveOriginalDestination(r bool) HubOption {
|
|||||||
|
|
||||||
type Hub struct {
|
type Hub struct {
|
||||||
conn *net.UDPConn
|
conn *net.UDPConn
|
||||||
|
connPacket net.PacketConn
|
||||||
cache chan *udp.Packet
|
cache chan *udp.Packet
|
||||||
capacity int
|
capacity int
|
||||||
recvOrigDest bool
|
recvOrigDest bool
|
||||||
@ -46,8 +50,9 @@ func ListenUDP(ctx context.Context, address net.Address, port net.Port, streamSe
|
|||||||
if sockopt != nil && sockopt.ReceiveOriginalDestAddress {
|
if sockopt != nil && sockopt.ReceiveOriginalDestAddress {
|
||||||
hub.recvOrigDest = true
|
hub.recvOrigDest = true
|
||||||
}
|
}
|
||||||
|
transportEnvironment := envctx.EnvironmentFromContext(ctx).(environment.TransportEnvironment)
|
||||||
udpConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{
|
listener := transportEnvironment.Listener()
|
||||||
|
udpConn, err := listener.ListenPacket(ctx, &net.UDPAddr{
|
||||||
IP: address.IP(),
|
IP: address.IP(),
|
||||||
Port: int(port),
|
Port: int(port),
|
||||||
}, sockopt)
|
}, sockopt)
|
||||||
@ -55,7 +60,12 @@ func ListenUDP(ctx context.Context, address net.Address, port net.Port, streamSe
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
newError("listening UDP on ", address, ":", port).WriteToLog()
|
newError("listening UDP on ", address, ":", port).WriteToLog()
|
||||||
hub.conn = udpConn.(*net.UDPConn)
|
if udpConnDirect, ok := udpConn.(*net.UDPConn); ok {
|
||||||
|
hub.conn = udpConnDirect
|
||||||
|
} else {
|
||||||
|
hub.connPacket = udpConn
|
||||||
|
}
|
||||||
|
|
||||||
hub.cache = make(chan *udp.Packet, hub.capacity)
|
hub.cache = make(chan *udp.Packet, hub.capacity)
|
||||||
|
|
||||||
go hub.start()
|
go hub.start()
|
||||||
@ -64,11 +74,21 @@ func ListenUDP(ctx context.Context, address net.Address, port net.Port, streamSe
|
|||||||
|
|
||||||
// Close implements net.Listener.
|
// Close implements net.Listener.
|
||||||
func (h *Hub) Close() error {
|
func (h *Hub) Close() error {
|
||||||
|
if h.connPacket != nil {
|
||||||
|
h.connPacket.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
h.conn.Close()
|
h.conn.Close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hub) WriteTo(payload []byte, dest net.Destination) (int, error) {
|
func (h *Hub) WriteTo(payload []byte, dest net.Destination) (int, error) {
|
||||||
|
if h.connPacket != nil {
|
||||||
|
return h.connPacket.WriteTo(payload, &net.UDPAddr{
|
||||||
|
IP: dest.Address.IP(),
|
||||||
|
Port: int(dest.Port),
|
||||||
|
})
|
||||||
|
}
|
||||||
return h.conn.WriteToUDP(payload, &net.UDPAddr{
|
return h.conn.WriteToUDP(payload, &net.UDPAddr{
|
||||||
IP: dest.Address.IP(),
|
IP: dest.Address.IP(),
|
||||||
Port: int(dest.Port),
|
Port: int(dest.Port),
|
||||||
@ -83,47 +103,76 @@ func (h *Hub) start() {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
buffer := buf.New()
|
buffer := buf.New()
|
||||||
var noob int
|
if h.conn != nil {
|
||||||
var addr *net.UDPAddr
|
var noob int
|
||||||
rawBytes := buffer.Extend(buf.Size)
|
var addr *net.UDPAddr
|
||||||
|
rawBytes := buffer.Extend(buf.Size)
|
||||||
n, noob, _, addr, err := ReadUDPMsg(h.conn, rawBytes, oobBytes)
|
n, noob, _, addr, err := ReadUDPMsg(h.conn, rawBytes, oobBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
newError("failed to read UDP msg").Base(err).WriteToLog()
|
newError("failed to read UDP msg").Base(err).WriteToLog()
|
||||||
buffer.Release()
|
buffer.Release()
|
||||||
break
|
break
|
||||||
}
|
|
||||||
buffer.Resize(0, int32(n))
|
|
||||||
|
|
||||||
if buffer.IsEmpty() {
|
|
||||||
buffer.Release()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
payload := &udp.Packet{
|
|
||||||
Payload: buffer,
|
|
||||||
Source: net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)),
|
|
||||||
}
|
|
||||||
if h.recvOrigDest && noob > 0 {
|
|
||||||
payload.Target = RetrieveOriginalDest(oobBytes[:noob])
|
|
||||||
if payload.Target.IsValid() {
|
|
||||||
newError("UDP original destination: ", payload.Target).AtDebug().WriteToLog()
|
|
||||||
} else {
|
|
||||||
newError("failed to read UDP original destination").WriteToLog()
|
|
||||||
}
|
}
|
||||||
}
|
buffer.Resize(0, int32(n))
|
||||||
|
|
||||||
select {
|
if buffer.IsEmpty() {
|
||||||
case c <- payload:
|
buffer.Release()
|
||||||
default:
|
continue
|
||||||
buffer.Release()
|
}
|
||||||
payload.Payload = nil
|
|
||||||
|
payload := &udp.Packet{
|
||||||
|
Payload: buffer,
|
||||||
|
Source: net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)),
|
||||||
|
}
|
||||||
|
if h.recvOrigDest && noob > 0 {
|
||||||
|
payload.Target = RetrieveOriginalDest(oobBytes[:noob])
|
||||||
|
if payload.Target.IsValid() {
|
||||||
|
newError("UDP original destination: ", payload.Target).AtDebug().WriteToLog()
|
||||||
|
} else {
|
||||||
|
newError("failed to read UDP original destination").WriteToLog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case c <- payload:
|
||||||
|
default:
|
||||||
|
buffer.Release()
|
||||||
|
payload.Payload = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rawBytes := buffer.Extend(buf.Size)
|
||||||
|
n, addr, err := h.connPacket.ReadFrom(rawBytes)
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to read UDP msg").Base(err).WriteToLog()
|
||||||
|
buffer.Release()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
buffer.Resize(0, int32(n))
|
||||||
|
|
||||||
|
if buffer.IsEmpty() {
|
||||||
|
buffer.Release()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := &udp.Packet{
|
||||||
|
Payload: buffer,
|
||||||
|
Source: net.DestinationFromAddr(addr),
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case c <- payload:
|
||||||
|
default:
|
||||||
|
buffer.Release()
|
||||||
|
payload.Payload = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Addr implements net.Listener.
|
// Addr implements net.Listener.
|
||||||
func (h *Hub) Addr() net.Addr {
|
func (h *Hub) Addr() net.Addr {
|
||||||
|
if h.conn == nil {
|
||||||
|
return h.connPacket.LocalAddr()
|
||||||
|
}
|
||||||
return h.conn.LocalAddr()
|
return h.conn.LocalAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user