1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-09 01:10:44 +00:00

Add trojan over xtls support (#334)

* Add trojan over xtls support

* Add comments

* improve PR quality

* improve PR quality

* add xtls-rprx-origin-udp443 and xtls-rprx-direct-udp443

Co-authored-by: Eken Chan <maskedeken@yahoo.com>
This commit is contained in:
ekenchan 2020-10-20 18:44:31 +08:00 committed by GitHub
parent b562f21ca2
commit 3fc985dd0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 288 additions and 332 deletions

View File

@ -21,6 +21,7 @@ type TrojanServerTarget struct {
Password string `json:"password"`
Email string `json:"email"`
Level byte `json:"level"`
Flow string `json:"flow"`
}
// TrojanClientConfig is configuration of trojan servers
@ -49,6 +50,7 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) {
}
account := &trojan.Account{
Password: rec.Password,
Flow: rec.Flow,
}
trojan := &protocol.ServerEndpoint{
Address: rec.Address.Build(),
@ -84,6 +86,7 @@ type TrojanUserConfig struct {
Password string `json:"password"`
Level byte `json:"level"`
Email string `json:"email"`
Flow string `json:"flow"`
}
// TrojanServerConfig is Inbound configuration
@ -106,6 +109,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
user := new(protocol.User)
account := &trojan.Account{
Password: rawUser.Password,
Flow: rawUser.Flow,
}
user.Email = rawUser.Email

View File

@ -188,8 +188,8 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
if err != nil {
return nil, err
}
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, "vless") {
return nil, newError("XTLS only supports VLESS for now.")
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, "vless") && !strings.EqualFold(c.Protocol, "trojan") {
return nil, newError("XTLS doesn't supports " + c.Protocol + " for now.")
}
receiverSettings.StreamSettings = ss
}
@ -258,8 +258,8 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
if err != nil {
return nil, err
}
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, "vless") {
return nil, newError("XTLS only supports VLESS for now.")
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, "vless") && !strings.EqualFold(c.Protocol, "trojan") {
return nil, newError("XTLS doesn't supports " + c.Protocol + " for now.")
}
senderSettings.StreamSettings = ss
}

View File

@ -18,6 +18,7 @@ import (
"v2ray.com/core/features/policy"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/xtls"
)
// Client is a inbound handler for trojan protocol
@ -83,6 +84,44 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
return newError("user account is not valid")
}
iConn := conn
if statConn, ok := iConn.(*internet.StatCouterConnection); ok {
iConn = statConn.Connection
}
connWriter := &ConnWriter{}
allowUDP443 := false
switch account.Flow {
case XRO + "-udp443", XRD + "-udp443":
allowUDP443 = true
account.Flow = account.Flow[:16]
fallthrough
case XRO, XRD:
if destination.Address.Family().IsDomain() && destination.Address.Domain() == muxCoolAddress {
return newError(account.Flow + " doesn't support Mux").AtWarning()
}
if destination.Network == net.Network_UDP {
if !allowUDP443 && destination.Port == 443 {
return newError(account.Flow + " stopped UDP/443").AtInfo()
}
} else { // enable XTLS only if making TCP request
if xtlsConn, ok := iConn.(*xtls.Conn); ok {
connWriter.Flow = account.Flow
xtlsConn.RPRX = true
if account.Flow == XRD {
xtlsConn.DirectMode = true
}
} else {
return newError(`failed to enable XTLS, maybe "security" is not "xtls"`).AtWarning()
}
}
case "":
default:
return newError("unsupported flow type: ", account.Flow).AtWarning()
}
sessionPolicy := c.policyManager.ForLevel(user.Level)
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
@ -92,7 +131,9 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
var bodyWriter buf.Writer
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
connWriter := &ConnWriter{Writer: bufferWriter, Target: destination, Account: account}
connWriter.Writer = bufferWriter
connWriter.Target = destination
connWriter.Account = account
if destination.Network == net.Network_UDP {
bodyWriter = &PacketWriter{Writer: connWriter, Target: destination}

View File

@ -13,6 +13,7 @@ import (
type MemoryAccount struct {
Password string
Key []byte
Flow string
}
// AsAccount implements protocol.AsAccount.
@ -22,6 +23,7 @@ func (a *Account) AsAccount() (protocol.Account, error) {
return &MemoryAccount{
Password: password,
Key: key,
Flow: a.Flow,
}, nil
}

View File

@ -1,404 +1,263 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.13.0
// source: proxy/trojan/config.proto
package trojan
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
math "math"
protocol "v2ray.com/core/common/protocol"
)
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)
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (x *Account) Reset() {
*x = Account{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_trojan_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Account) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_proxy_trojan_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 Account.ProtoReflect.Descriptor instead.
func (m *Account) Reset() { *m = Account{} }
func (m *Account) String() string { return proto.CompactTextString(m) }
func (*Account) ProtoMessage() {}
func (*Account) Descriptor() ([]byte, []int) {
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{0}
return fileDescriptor_c2cd7d26d2c3a1c9, []int{0}
}
func (x *Account) GetPassword() string {
if x != nil {
return x.Password
func (m *Account) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Account.Unmarshal(m, b)
}
func (m *Account) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Account.Marshal(b, m, deterministic)
}
func (m *Account) XXX_Merge(src proto.Message) {
xxx_messageInfo_Account.Merge(m, src)
}
func (m *Account) XXX_Size() int {
return xxx_messageInfo_Account.Size(m)
}
func (m *Account) XXX_DiscardUnknown() {
xxx_messageInfo_Account.DiscardUnknown(m)
}
var xxx_messageInfo_Account proto.InternalMessageInfo
func (m *Account) GetPassword() string {
if m != nil {
return m.Password
}
return ""
}
func (m *Account) GetFlow() string {
if m != nil {
return m.Flow
}
return ""
}
type Fallback struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Alpn string `protobuf:"bytes,1,opt,name=alpn,proto3" json:"alpn,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
Dest string `protobuf:"bytes,4,opt,name=dest,proto3" json:"dest,omitempty"`
Xver uint64 `protobuf:"varint,5,opt,name=xver,proto3" json:"xver,omitempty"`
Alpn string `protobuf:"bytes,1,opt,name=alpn,proto3" json:"alpn,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
Dest string `protobuf:"bytes,4,opt,name=dest,proto3" json:"dest,omitempty"`
Xver uint64 `protobuf:"varint,5,opt,name=xver,proto3" json:"xver,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (x *Fallback) Reset() {
*x = Fallback{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_trojan_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Fallback) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Fallback) ProtoMessage() {}
func (x *Fallback) ProtoReflect() protoreflect.Message {
mi := &file_proxy_trojan_config_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 Fallback.ProtoReflect.Descriptor instead.
func (m *Fallback) Reset() { *m = Fallback{} }
func (m *Fallback) String() string { return proto.CompactTextString(m) }
func (*Fallback) ProtoMessage() {}
func (*Fallback) Descriptor() ([]byte, []int) {
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{1}
return fileDescriptor_c2cd7d26d2c3a1c9, []int{1}
}
func (x *Fallback) GetAlpn() string {
if x != nil {
return x.Alpn
func (m *Fallback) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Fallback.Unmarshal(m, b)
}
func (m *Fallback) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Fallback.Marshal(b, m, deterministic)
}
func (m *Fallback) XXX_Merge(src proto.Message) {
xxx_messageInfo_Fallback.Merge(m, src)
}
func (m *Fallback) XXX_Size() int {
return xxx_messageInfo_Fallback.Size(m)
}
func (m *Fallback) XXX_DiscardUnknown() {
xxx_messageInfo_Fallback.DiscardUnknown(m)
}
var xxx_messageInfo_Fallback proto.InternalMessageInfo
func (m *Fallback) GetAlpn() string {
if m != nil {
return m.Alpn
}
return ""
}
func (x *Fallback) GetPath() string {
if x != nil {
return x.Path
func (m *Fallback) GetPath() string {
if m != nil {
return m.Path
}
return ""
}
func (x *Fallback) GetType() string {
if x != nil {
return x.Type
func (m *Fallback) GetType() string {
if m != nil {
return m.Type
}
return ""
}
func (x *Fallback) GetDest() string {
if x != nil {
return x.Dest
func (m *Fallback) GetDest() string {
if m != nil {
return m.Dest
}
return ""
}
func (x *Fallback) GetXver() uint64 {
if x != nil {
return x.Xver
func (m *Fallback) GetXver() uint64 {
if m != nil {
return m.Xver
}
return 0
}
type ClientConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"`
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (x *ClientConfig) Reset() {
*x = ClientConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_trojan_config_proto_msgTypes[2]
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_proxy_trojan_config_proto_msgTypes[2]
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 (m *ClientConfig) Reset() { *m = ClientConfig{} }
func (m *ClientConfig) String() string { return proto.CompactTextString(m) }
func (*ClientConfig) ProtoMessage() {}
func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{2}
return fileDescriptor_c2cd7d26d2c3a1c9, []int{2}
}
func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {
if x != nil {
return x.Server
func (m *ClientConfig) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ClientConfig.Unmarshal(m, b)
}
func (m *ClientConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ClientConfig.Marshal(b, m, deterministic)
}
func (m *ClientConfig) XXX_Merge(src proto.Message) {
xxx_messageInfo_ClientConfig.Merge(m, src)
}
func (m *ClientConfig) XXX_Size() int {
return xxx_messageInfo_ClientConfig.Size(m)
}
func (m *ClientConfig) XXX_DiscardUnknown() {
xxx_messageInfo_ClientConfig.DiscardUnknown(m)
}
var xxx_messageInfo_ClientConfig proto.InternalMessageInfo
func (m *ClientConfig) GetServer() []*protocol.ServerEndpoint {
if m != nil {
return m.Server
}
return nil
}
type ServerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Users []*protocol.User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
Fallbacks []*Fallback `protobuf:"bytes,3,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"`
Users []*protocol.User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
Fallbacks []*Fallback `protobuf:"bytes,3,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (x *ServerConfig) Reset() {
*x = ServerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_trojan_config_proto_msgTypes[3]
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_proxy_trojan_config_proto_msgTypes[3]
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 (m *ServerConfig) Reset() { *m = ServerConfig{} }
func (m *ServerConfig) String() string { return proto.CompactTextString(m) }
func (*ServerConfig) ProtoMessage() {}
func (*ServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_trojan_config_proto_rawDescGZIP(), []int{3}
return fileDescriptor_c2cd7d26d2c3a1c9, []int{3}
}
func (x *ServerConfig) GetUsers() []*protocol.User {
if x != nil {
return x.Users
func (m *ServerConfig) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ServerConfig.Unmarshal(m, b)
}
func (m *ServerConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ServerConfig.Marshal(b, m, deterministic)
}
func (m *ServerConfig) XXX_Merge(src proto.Message) {
xxx_messageInfo_ServerConfig.Merge(m, src)
}
func (m *ServerConfig) XXX_Size() int {
return xxx_messageInfo_ServerConfig.Size(m)
}
func (m *ServerConfig) XXX_DiscardUnknown() {
xxx_messageInfo_ServerConfig.DiscardUnknown(m)
}
var xxx_messageInfo_ServerConfig proto.InternalMessageInfo
func (m *ServerConfig) GetUsers() []*protocol.User {
if m != nil {
return m.Users
}
return nil
}
func (x *ServerConfig) GetFallbacks() []*Fallback {
if x != nil {
return x.Fallbacks
func (m *ServerConfig) GetFallbacks() []*Fallback {
if m != nil {
return m.Fallbacks
}
return nil
}
var File_proxy_trojan_config_proto protoreflect.FileDescriptor
var file_proxy_trojan_config_proto_rawDesc = []byte{
0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2f, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72,
0x6f, 0x6a, 0x61, 0x6e, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x25, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a,
0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x6e, 0x0a, 0x08, 0x46, 0x61,
0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12,
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79,
0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x05,
0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x52, 0x0a, 0x0c, 0x43, 0x6c,
0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a, 0x06, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 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, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e,
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x87,
0x01, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x36, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20,
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, 0x55, 0x73, 0x65, 0x72,
0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x3f, 0x0a, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62,
0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72,
0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x66,
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x42, 0x56, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x1b, 0x76, 0x32, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f,
0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0xaa, 0x02, 0x17, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43,
0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x54, 0x72, 0x6f, 0x6a, 0x61, 0x6e,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
func init() {
proto.RegisterType((*Account)(nil), "v2ray.core.proxy.trojan.Account")
proto.RegisterType((*Fallback)(nil), "v2ray.core.proxy.trojan.Fallback")
proto.RegisterType((*ClientConfig)(nil), "v2ray.core.proxy.trojan.ClientConfig")
proto.RegisterType((*ServerConfig)(nil), "v2ray.core.proxy.trojan.ServerConfig")
}
var (
file_proxy_trojan_config_proto_rawDescOnce sync.Once
file_proxy_trojan_config_proto_rawDescData = file_proxy_trojan_config_proto_rawDesc
)
func file_proxy_trojan_config_proto_rawDescGZIP() []byte {
file_proxy_trojan_config_proto_rawDescOnce.Do(func() {
file_proxy_trojan_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_trojan_config_proto_rawDescData)
})
return file_proxy_trojan_config_proto_rawDescData
func init() {
proto.RegisterFile("proxy/trojan/config.proto", fileDescriptor_c2cd7d26d2c3a1c9)
}
var file_proxy_trojan_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_proxy_trojan_config_proto_goTypes = []interface{}{
(*Account)(nil), // 0: v2ray.core.proxy.trojan.Account
(*Fallback)(nil), // 1: v2ray.core.proxy.trojan.Fallback
(*ClientConfig)(nil), // 2: v2ray.core.proxy.trojan.ClientConfig
(*ServerConfig)(nil), // 3: v2ray.core.proxy.trojan.ServerConfig
(*protocol.ServerEndpoint)(nil), // 4: v2ray.core.common.protocol.ServerEndpoint
(*protocol.User)(nil), // 5: v2ray.core.common.protocol.User
}
var file_proxy_trojan_config_proto_depIdxs = []int32{
4, // 0: v2ray.core.proxy.trojan.ClientConfig.server:type_name -> v2ray.core.common.protocol.ServerEndpoint
5, // 1: v2ray.core.proxy.trojan.ServerConfig.users:type_name -> v2ray.core.common.protocol.User
1, // 2: v2ray.core.proxy.trojan.ServerConfig.fallbacks:type_name -> v2ray.core.proxy.trojan.Fallback
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_proxy_trojan_config_proto_init() }
func file_proxy_trojan_config_proto_init() {
if File_proxy_trojan_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_trojan_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Account); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_trojan_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Fallback); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_trojan_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ClientConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_trojan_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
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_proxy_trojan_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_trojan_config_proto_goTypes,
DependencyIndexes: file_proxy_trojan_config_proto_depIdxs,
MessageInfos: file_proxy_trojan_config_proto_msgTypes,
}.Build()
File_proxy_trojan_config_proto = out.File
file_proxy_trojan_config_proto_rawDesc = nil
file_proxy_trojan_config_proto_goTypes = nil
file_proxy_trojan_config_proto_depIdxs = nil
var fileDescriptor_c2cd7d26d2c3a1c9 = []byte{
// 348 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xbd, 0x4e, 0xfb, 0x30,
0x14, 0xc5, 0x95, 0x7e, 0xfd, 0x5b, 0xff, 0x3b, 0x65, 0x69, 0x48, 0x97, 0x34, 0x53, 0xc5, 0xe0,
0x48, 0x45, 0x42, 0x62, 0x42, 0xb4, 0x82, 0xb9, 0x32, 0xd0, 0x81, 0x05, 0xb9, 0xae, 0x0b, 0x85,
0xc4, 0xd7, 0xb2, 0xdd, 0x8f, 0x3c, 0x01, 0xef, 0xc2, 0x53, 0x22, 0xdb, 0x09, 0x54, 0x48, 0x65,
0x3b, 0x39, 0xe7, 0xfc, 0xae, 0x72, 0x6f, 0x82, 0xce, 0xa4, 0x82, 0x43, 0x99, 0x19, 0x05, 0x6f,
0x54, 0x64, 0x0c, 0xc4, 0x7a, 0xf3, 0x82, 0xa5, 0x02, 0x03, 0xe1, 0x60, 0x37, 0x51, 0xb4, 0xc4,
0x0c, 0x14, 0xc7, 0xae, 0x85, 0x7d, 0x2b, 0x8e, 0x19, 0x14, 0x05, 0x88, 0xcc, 0xd5, 0x18, 0xe4,
0xd9, 0x56, 0x73, 0xe5, 0xa1, 0x78, 0xf4, 0x3b, 0xd3, 0x5c, 0xed, 0xb8, 0x7a, 0xd6, 0x92, 0x33,
0x5f, 0x49, 0xaf, 0xd0, 0xbf, 0x1b, 0xc6, 0x60, 0x2b, 0x4c, 0x18, 0xa3, 0xae, 0xa4, 0x5a, 0xef,
0x41, 0xad, 0xa2, 0x20, 0x09, 0xc6, 0x3d, 0xf2, 0xfd, 0x1c, 0x86, 0xa8, 0xb5, 0xce, 0x61, 0x1f,
0x35, 0x9c, 0xef, 0x74, 0x2a, 0x50, 0xf7, 0x8e, 0xe6, 0xf9, 0x92, 0xb2, 0x77, 0x9b, 0xd3, 0x5c,
0x8a, 0x8a, 0x73, 0xda, 0x7a, 0x92, 0x9a, 0xd7, 0x9a, 0xb1, 0xda, 0x7a, 0xa6, 0x94, 0x3c, 0x6a,
0x7a, 0xcf, 0x6a, 0xeb, 0xad, 0xb8, 0x36, 0x51, 0xcb, 0x7b, 0x56, 0x5b, 0xef, 0xb0, 0xe3, 0x2a,
0x6a, 0x27, 0xc1, 0xb8, 0x45, 0x9c, 0x4e, 0x09, 0xea, 0xcf, 0xf2, 0x0d, 0x17, 0x66, 0xe6, 0x0e,
0x13, 0x4e, 0x51, 0xc7, 0xef, 0x13, 0x05, 0x49, 0x73, 0xfc, 0x7f, 0x72, 0x8e, 0x8f, 0x6e, 0xe4,
0x37, 0xc7, 0xf5, 0xe6, 0xf8, 0xde, 0x35, 0x6f, 0xc5, 0x4a, 0xc2, 0x46, 0x18, 0x52, 0x91, 0xe9,
0x47, 0x80, 0xfa, 0x3e, 0xaa, 0x86, 0x5e, 0xa2, 0xb6, 0x3d, 0xa0, 0xae, 0x66, 0x26, 0x7f, 0xcd,
0x7c, 0xd4, 0x5c, 0x11, 0x5f, 0x0f, 0xaf, 0x51, 0x6f, 0x5d, 0x1d, 0x43, 0x47, 0x4d, 0xc7, 0x8e,
0xf0, 0x89, 0x6f, 0x86, 0xeb, 0xb3, 0x91, 0x1f, 0x66, 0xba, 0x40, 0x43, 0x06, 0xc5, 0x29, 0x64,
0x1e, 0x3c, 0x0d, 0xeb, 0xa8, 0xc8, 0x6c, 0x9c, 0x1d, 0xff, 0x2b, 0x9f, 0x8d, 0xc1, 0x62, 0x42,
0x68, 0x89, 0x67, 0x16, 0x9c, 0x3b, 0xf0, 0xc1, 0x25, 0xcb, 0x8e, 0x7b, 0xdd, 0x8b, 0xaf, 0x00,
0x00, 0x00, 0xff, 0xff, 0xb0, 0x31, 0x74, 0x85, 0x5c, 0x02, 0x00, 0x00,
}

View File

@ -21,9 +21,17 @@ var (
const (
maxLength = 8192
// XRO is constant for XTLS origin mode
XRO = "xtls-rprx-origin"
// XRD is constant for XTLS direct mode
XRD = "xtls-rprx-direct"
commandTCP byte = 1
commandUDP byte = 3
// for xtls
commandXRO byte = 0xf1 // XTLS origin mode
commandXRD byte = 0xf2 // XTLS direct mode
)
// ConnWriter is TCP Connection Writer Wrapper for trojan protocol
@ -31,6 +39,7 @@ type ConnWriter struct {
io.Writer
Target net.Destination
Account *MemoryAccount
Flow string
headerSent bool
}
@ -67,6 +76,10 @@ func (c *ConnWriter) writeHeader() error {
command := commandTCP
if c.Target.Network == net.Network_UDP {
command = commandUDP
} else if c.Flow == XRO {
command = commandXRO
} else if c.Flow == XRD {
command = commandXRD
}
if _, err := buffer.Write(c.Account.Key); err != nil {
@ -160,6 +173,7 @@ func (w *PacketWriter) writePacket(payload []byte, dest net.Destination) (int, e
type ConnReader struct {
io.Reader
Target net.Destination
Flow string
headerParsed bool
}
@ -183,6 +197,10 @@ func (c *ConnReader) ParseHeader() error {
network := net.Network_TCP
if command[0] == commandUDP {
network = net.Network_UDP
} else if command[0] == commandXRO {
c.Flow = XRO
} else if command[0] == commandXRD {
c.Flow = XRD
}
addr, port, err := addrParser.ReadAddressPort(nil, c.Reader)

View File

@ -185,6 +185,34 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
}
// handle tcp request
account, ok := user.Account.(*MemoryAccount)
if !ok {
return newError("user account is not valid")
}
switch clientReader.Flow {
case XRO, XRD:
if account.Flow == clientReader.Flow {
if destination.Address.Family().IsDomain() && destination.Address.Domain() == muxCoolAddress {
return newError("XTLS doesn't support Mux").AtWarning()
}
if xtlsConn, ok := iConn.(*xtls.Conn); ok {
xtlsConn.RPRX = true
if clientReader.Flow == XRD {
xtlsConn.DirectMode = true
}
} else {
return newError(`failed to enable XTLS, maybe "security" is not "xtls"`).AtWarning()
}
} else {
return newError("unable to use ", clientReader.Flow).AtWarning()
}
case "":
default:
return newError("unsupported flow type: ", account.Flow).AtWarning()
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: conn.RemoteAddr(),

View File

@ -1 +1,5 @@
package trojan
const (
muxCoolAddress = "v1.mux.cool"
)