Remove mtproto

This commit is contained in:
yuhan6665 2023-06-06 23:38:34 -04:00
parent 038f849dd3
commit c9f517108c
13 changed files with 0 additions and 876 deletions

View file

@ -1,67 +0,0 @@
package conf
import (
"encoding/hex"
"encoding/json"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/proxy/mtproto"
)
type MTProtoAccount struct {
Secret string `json:"secret"`
}
// Build implements Buildable
func (a *MTProtoAccount) Build() (*mtproto.Account, error) {
if len(a.Secret) != 32 {
return nil, newError("MTProto secret must have 32 chars")
}
secret, err := hex.DecodeString(a.Secret)
if err != nil {
return nil, newError("failed to decode secret: ", a.Secret).Base(err)
}
return &mtproto.Account{
Secret: secret,
}, nil
}
type MTProtoServerConfig struct {
Users []json.RawMessage `json:"users"`
}
func (c *MTProtoServerConfig) Build() (proto.Message, error) {
config := &mtproto.ServerConfig{}
if len(c.Users) == 0 {
return nil, newError("zero MTProto users configured.")
}
config.User = make([]*protocol.User, len(c.Users))
for idx, rawData := range c.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawData, user); err != nil {
return nil, newError("invalid MTProto user").Base(err)
}
account := new(MTProtoAccount)
if err := json.Unmarshal(rawData, account); err != nil {
return nil, newError("invalid MTProto user").Base(err)
}
accountProto, err := account.Build()
if err != nil {
return nil, newError("failed to parse MTProto user").Base(err)
}
user.Account = serial.ToTypedMessage(accountProto)
config.User[idx] = user
}
return config, nil
}
type MTProtoClientConfig struct{}
func (c *MTProtoClientConfig) Build() (proto.Message, error) {
config := new(mtproto.ClientConfig)
return config, nil
}

View file

@ -1,40 +0,0 @@
package conf_test
import (
"testing"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
. "github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/proxy/mtproto"
)
func TestMTProtoServerConfig(t *testing.T) {
creator := func() Buildable {
return new(MTProtoServerConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"users": [{
"email": "love@example.com",
"level": 1,
"secret": "b0cbcef5a486d9636472ac27f8e11a9d"
}]
}`,
Parser: loadJSON(creator),
Output: &mtproto.ServerConfig{
User: []*protocol.User{
{
Email: "love@example.com",
Level: 1,
Account: serial.ToTypedMessage(&mtproto.Account{
Secret: []byte{176, 203, 206, 245, 164, 134, 217, 99, 100, 114, 172, 39, 248, 225, 26, 157},
}),
},
},
},
},
})
}

View file

@ -24,7 +24,6 @@ var (
"vless": func() interface{} { return new(VLessInboundConfig) },
"vmess": func() interface{} { return new(VMessInboundConfig) },
"trojan": func() interface{} { return new(TrojanServerConfig) },
"mtproto": func() interface{} { return new(MTProtoServerConfig) },
}, "protocol", "settings")
outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
@ -37,7 +36,6 @@ var (
"vless": func() interface{} { return new(VLessOutboundConfig) },
"vmess": func() interface{} { return new(VMessOutboundConfig) },
"trojan": func() interface{} { return new(TrojanClientConfig) },
"mtproto": func() interface{} { return new(MTProtoClientConfig) },
"dns": func() interface{} { return new(DNSOutboundConfig) },
"wireguard": func() interface{} { return new(WireGuardConfig) },
}, "protocol", "settings")

View file

@ -40,7 +40,6 @@ import (
_ "github.com/xtls/xray-core/proxy/freedom"
_ "github.com/xtls/xray-core/proxy/http"
_ "github.com/xtls/xray-core/proxy/loopback"
_ "github.com/xtls/xray-core/proxy/mtproto"
_ "github.com/xtls/xray-core/proxy/shadowsocks"
_ "github.com/xtls/xray-core/proxy/socks"
_ "github.com/xtls/xray-core/proxy/trojan"

View file

@ -1,148 +0,0 @@
package mtproto
import (
"context"
"crypto/rand"
"crypto/sha256"
"io"
"sync"
"github.com/xtls/xray-core/common"
)
const (
HeaderSize = 64
)
type SessionContext struct {
ConnectionType [4]byte
DataCenterID uint16
}
func DefaultSessionContext() SessionContext {
return SessionContext{
ConnectionType: [4]byte{0xef, 0xef, 0xef, 0xef},
DataCenterID: 0,
}
}
type contextKey int32
const (
sessionContextKey contextKey = iota
)
func ContextWithSessionContext(ctx context.Context, c SessionContext) context.Context {
return context.WithValue(ctx, sessionContextKey, c)
}
func SessionContextFromContext(ctx context.Context) SessionContext {
if c := ctx.Value(sessionContextKey); c != nil {
return c.(SessionContext)
}
return DefaultSessionContext()
}
type Authentication struct {
Header [HeaderSize]byte
DecodingKey [32]byte
EncodingKey [32]byte
DecodingNonce [16]byte
EncodingNonce [16]byte
}
func (a *Authentication) DataCenterID() uint16 {
x := ((int16(a.Header[61]) << 8) | int16(a.Header[60]))
if x < 0 {
x = -x
}
return uint16(x) - 1
}
func (a *Authentication) ConnectionType() [4]byte {
var x [4]byte
copy(x[:], a.Header[56:60])
return x
}
func (a *Authentication) ApplySecret(b []byte) {
a.DecodingKey = sha256.Sum256(append(a.DecodingKey[:], b...))
a.EncodingKey = sha256.Sum256(append(a.EncodingKey[:], b...))
}
func generateRandomBytes(random []byte, connType [4]byte) {
for {
common.Must2(rand.Read(random))
if random[0] == 0xef {
continue
}
val := (uint32(random[3]) << 24) | (uint32(random[2]) << 16) | (uint32(random[1]) << 8) | uint32(random[0])
if val == 0x44414548 || val == 0x54534f50 || val == 0x20544547 || val == 0x4954504f || val == 0xeeeeeeee {
continue
}
if (uint32(random[7])<<24)|(uint32(random[6])<<16)|(uint32(random[5])<<8)|uint32(random[4]) == 0x00000000 {
continue
}
copy(random[56:60], connType[:])
return
}
}
func NewAuthentication(sc SessionContext) *Authentication {
auth := getAuthenticationObject()
random := auth.Header[:]
generateRandomBytes(random, sc.ConnectionType)
copy(auth.EncodingKey[:], random[8:])
copy(auth.EncodingNonce[:], random[8+32:])
keyivInverse := Inverse(random[8 : 8+32+16])
copy(auth.DecodingKey[:], keyivInverse)
copy(auth.DecodingNonce[:], keyivInverse[32:])
return auth
}
func ReadAuthentication(reader io.Reader) (*Authentication, error) {
auth := getAuthenticationObject()
if _, err := io.ReadFull(reader, auth.Header[:]); err != nil {
putAuthenticationObject(auth)
return nil, err
}
copy(auth.DecodingKey[:], auth.Header[8:])
copy(auth.DecodingNonce[:], auth.Header[8+32:])
keyivInverse := Inverse(auth.Header[8 : 8+32+16])
copy(auth.EncodingKey[:], keyivInverse)
copy(auth.EncodingNonce[:], keyivInverse[32:])
return auth, nil
}
// Inverse returns a new byte array. It is a sequence of bytes when the input is read from end to beginning.Inverse
// Visible for testing only.
func Inverse(b []byte) []byte {
lenb := len(b)
b2 := make([]byte, lenb)
for i, v := range b {
b2[lenb-i-1] = v
}
return b2
}
var authPool = sync.Pool{
New: func() interface{} {
return new(Authentication)
},
}
func getAuthenticationObject() *Authentication {
return authPool.Get().(*Authentication)
}
func putAuthenticationObject(auth *Authentication) {
authPool.Put(auth)
}

View file

@ -1,52 +0,0 @@
package mtproto_test
import (
"bytes"
"crypto/rand"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/xtls/xray-core/common"
. "github.com/xtls/xray-core/proxy/mtproto"
)
func TestInverse(t *testing.T) {
const size = 64
b := make([]byte, 64)
for b[0] == b[size-1] {
common.Must2(rand.Read(b))
}
bi := Inverse(b)
if b[0] == bi[0] {
t.Fatal("seems bytes are not inversed: ", b[0], "vs", bi[0])
}
bii := Inverse(bi)
if r := cmp.Diff(bii, b); r != "" {
t.Fatal(r)
}
}
func TestAuthenticationReadWrite(t *testing.T) {
a := NewAuthentication(DefaultSessionContext())
b := bytes.NewReader(a.Header[:])
a2, err := ReadAuthentication(b)
common.Must(err)
if r := cmp.Diff(a.EncodingKey[:], a2.DecodingKey[:]); r != "" {
t.Error("decoding key: ", r)
}
if r := cmp.Diff(a.EncodingNonce[:], a2.DecodingNonce[:]); r != "" {
t.Error("decoding nonce: ", r)
}
if r := cmp.Diff(a.DecodingKey[:], a2.EncodingKey[:]); r != "" {
t.Error("encoding key: ", r)
}
if r := cmp.Diff(a.DecodingNonce[:], a2.EncodingNonce[:]); r != "" {
t.Error("encoding nonce: ", r)
}
}

View file

@ -1,76 +0,0 @@
package mtproto
import (
"context"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
)
type Client struct{}
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
return &Client{}, nil
}
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("unknown destination.")
}
dest := outbound.Target
if dest.Network != net.Network_TCP {
return newError("not TCP traffic", dest)
}
conn, err := dialer.Dial(ctx, dest)
if err != nil {
return newError("failed to dial to ", dest).Base(err).AtWarning()
}
defer conn.Close()
sc := SessionContextFromContext(ctx)
auth := NewAuthentication(sc)
defer putAuthenticationObject(auth)
request := func() error {
encryptor := crypto.NewAesCTRStream(auth.EncodingKey[:], auth.EncodingNonce[:])
var header [HeaderSize]byte
encryptor.XORKeyStream(header[:], auth.Header[:])
copy(header[:56], auth.Header[:])
if _, err := conn.Write(header[:]); err != nil {
return newError("failed to write auth header").Base(err)
}
connWriter := buf.NewWriter(crypto.NewCryptionWriter(encryptor, conn))
return buf.Copy(link.Reader, connWriter)
}
response := func() error {
decryptor := crypto.NewAesCTRStream(auth.DecodingKey[:], auth.DecodingNonce[:])
connReader := buf.NewReader(crypto.NewCryptionReader(decryptor, conn))
return buf.Copy(connReader, link.Writer)
}
responseDoneAndCloseWriter := task.OnSuccess(response, task.Close(link.Writer))
if err := task.Run(ctx, request, responseDoneAndCloseWriter); err != nil {
return newError("connection ends").Base(err)
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewClient(ctx, config.(*ClientConfig))
}))
}

View file

@ -1,24 +0,0 @@
package mtproto
import (
"github.com/xtls/xray-core/common/protocol"
)
func (a *Account) Equals(another protocol.Account) bool {
aa, ok := another.(*Account)
if !ok {
return false
}
if len(a.Secret) != len(aa.Secret) {
return false
}
for i, v := range a.Secret {
if v != aa.Secret[i] {
return false
}
}
return true
}

View file

@ -1,272 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.12
// source: proxy/mtproto/config.proto
package mtproto
import (
protocol "github.com/xtls/xray-core/common/protocol"
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 Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Secret []byte `protobuf:"bytes,1,opt,name=secret,proto3" json:"secret,omitempty"`
}
func (x *Account) Reset() {
*x = Account{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_mtproto_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_mtproto_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 (*Account) Descriptor() ([]byte, []int) {
return file_proxy_mtproto_config_proto_rawDescGZIP(), []int{0}
}
func (x *Account) GetSecret() []byte {
if x != nil {
return x.Secret
}
return nil
}
type ServerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// User is a list of users that allowed to connect to this inbound.
// Although this is a repeated field, only the first user is effective for
// now.
User []*protocol.User `protobuf:"bytes,1,rep,name=user,proto3" json:"user,omitempty"`
}
func (x *ServerConfig) Reset() {
*x = ServerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_mtproto_config_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_proxy_mtproto_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 ServerConfig.ProtoReflect.Descriptor instead.
func (*ServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_mtproto_config_proto_rawDescGZIP(), []int{1}
}
func (x *ServerConfig) GetUser() []*protocol.User {
if x != nil {
return x.User
}
return nil
}
type ClientConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ClientConfig) Reset() {
*x = ClientConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_mtproto_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_mtproto_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 (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_mtproto_config_proto_rawDescGZIP(), []int{2}
}
var File_proxy_mtproto_config_proto protoreflect.FileDescriptor
var file_proxy_mtproto_config_proto_rawDesc = []byte{
0x0a, 0x1a, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x6d, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x6d, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f,
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, 0x22, 0x21, 0x0a, 0x07,
0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22,
0x3e, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x2e, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22,
0x0e, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42,
0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78,
0x79, 0x2e, 0x6d, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x6d, 0x74, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78,
0x79, 0x2e, 0x4d, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_proxy_mtproto_config_proto_rawDescOnce sync.Once
file_proxy_mtproto_config_proto_rawDescData = file_proxy_mtproto_config_proto_rawDesc
)
func file_proxy_mtproto_config_proto_rawDescGZIP() []byte {
file_proxy_mtproto_config_proto_rawDescOnce.Do(func() {
file_proxy_mtproto_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_mtproto_config_proto_rawDescData)
})
return file_proxy_mtproto_config_proto_rawDescData
}
var file_proxy_mtproto_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_proxy_mtproto_config_proto_goTypes = []interface{}{
(*Account)(nil), // 0: xray.proxy.mtproto.Account
(*ServerConfig)(nil), // 1: xray.proxy.mtproto.ServerConfig
(*ClientConfig)(nil), // 2: xray.proxy.mtproto.ClientConfig
(*protocol.User)(nil), // 3: xray.common.protocol.User
}
var file_proxy_mtproto_config_proto_depIdxs = []int32{
3, // 0: xray.proxy.mtproto.ServerConfig.user:type_name -> xray.common.protocol.User
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_proxy_mtproto_config_proto_init() }
func file_proxy_mtproto_config_proto_init() {
if File_proxy_mtproto_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_mtproto_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_mtproto_config_proto_msgTypes[1].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
}
}
file_proxy_mtproto_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
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_mtproto_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_mtproto_config_proto_goTypes,
DependencyIndexes: file_proxy_mtproto_config_proto_depIdxs,
MessageInfos: file_proxy_mtproto_config_proto_msgTypes,
}.Build()
File_proxy_mtproto_config_proto = out.File
file_proxy_mtproto_config_proto_rawDesc = nil
file_proxy_mtproto_config_proto_goTypes = nil
file_proxy_mtproto_config_proto_depIdxs = nil
}

View file

@ -1,22 +0,0 @@
syntax = "proto3";
package xray.proxy.mtproto;
option csharp_namespace = "Xray.Proxy.Mtproto";
option go_package = "github.com/xtls/xray-core/proxy/mtproto";
option java_package = "com.xray.proxy.mtproto";
option java_multiple_files = true;
import "common/protocol/user.proto";
message Account {
bytes secret = 1;
}
message ServerConfig {
// User is a list of users that allowed to connect to this inbound.
// Although this is a repeated field, only the first user is effective for
// now.
repeated xray.common.protocol.User user = 1;
}
message ClientConfig {}

View file

@ -1,9 +0,0 @@
package mtproto
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View file

@ -1,3 +0,0 @@
package mtproto
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen

View file

@ -1,160 +0,0 @@
package mtproto
import (
"bytes"
"context"
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
)
var dcList = []net.Address{
net.ParseAddress("149.154.175.50"),
net.ParseAddress("149.154.167.51"),
net.ParseAddress("149.154.175.100"),
net.ParseAddress("149.154.167.91"),
net.ParseAddress("149.154.171.5"),
}
type Server struct {
user *protocol.User
account *Account
policy policy.Manager
}
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if len(config.User) == 0 {
return nil, newError("no user configured.")
}
user := config.User[0]
rawAccount, err := config.User[0].GetTypedAccount()
if err != nil {
return nil, newError("invalid account").Base(err)
}
account, ok := rawAccount.(*Account)
if !ok {
return nil, newError("not a MTProto account")
}
v := core.MustFromContext(ctx)
return &Server{
user: user,
account: account,
policy: v.GetFeature(policy.ManagerType()).(policy.Manager),
}, nil
}
func (s *Server) Network() []net.Network {
return []net.Network{net.Network_TCP}
}
var (
ctype1 = []byte{0xef, 0xef, 0xef, 0xef}
ctype2 = []byte{0xee, 0xee, 0xee, 0xee}
)
func isValidConnectionType(c [4]byte) bool {
if bytes.Equal(c[:], ctype1) {
return true
}
if bytes.Equal(c[:], ctype2) {
return true
}
return false
}
func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
sPolicy := s.policy.ForLevel(s.user.Level)
if err := conn.SetDeadline(time.Now().Add(sPolicy.Timeouts.Handshake)); err != nil {
newError("failed to set deadline").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
auth, err := ReadAuthentication(conn)
if err != nil {
return newError("failed to read authentication header").Base(err)
}
defer putAuthenticationObject(auth)
if err := conn.SetDeadline(time.Time{}); err != nil {
newError("failed to clear deadline").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
auth.ApplySecret(s.account.Secret)
decryptor := crypto.NewAesCTRStream(auth.DecodingKey[:], auth.DecodingNonce[:])
decryptor.XORKeyStream(auth.Header[:], auth.Header[:])
ct := auth.ConnectionType()
if !isValidConnectionType(ct) {
return newError("invalid connection type: ", ct)
}
dcID := auth.DataCenterID()
if dcID >= uint16(len(dcList)) {
return newError("invalid datacenter id: ", dcID)
}
dest := net.Destination{
Network: net.Network_TCP,
Address: dcList[dcID],
Port: net.Port(443),
}
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sPolicy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, sPolicy.Buffer)
sc := SessionContext{
ConnectionType: ct,
DataCenterID: dcID,
}
ctx = ContextWithSessionContext(ctx, sc)
link, err := dispatcher.Dispatch(ctx, dest)
if err != nil {
return newError("failed to dispatch request to: ", dest).Base(err)
}
request := func() error {
defer timer.SetTimeout(sPolicy.Timeouts.DownlinkOnly)
reader := buf.NewReader(crypto.NewCryptionReader(decryptor, conn))
return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer))
}
response := func() error {
defer timer.SetTimeout(sPolicy.Timeouts.UplinkOnly)
encryptor := crypto.NewAesCTRStream(auth.EncodingKey[:], auth.EncodingNonce[:])
writer := buf.NewWriter(crypto.NewCryptionWriter(encryptor, conn))
return buf.Copy(link.Reader, writer, buf.UpdateActivity(timer))
}
responseDoneAndCloseWriter := task.OnSuccess(response, task.Close(link.Writer))
if err := task.Run(ctx, request, responseDoneAndCloseWriter); err != nil {
common.Interrupt(link.Reader)
common.Interrupt(link.Writer)
return newError("connection ends").Base(err)
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewServer(ctx, config.(*ServerConfig))
}))
}