github.com/xraypb/Xray-core@v1.8.1/proxy/mtproto/client.go (about)

     1  package mtproto
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/xraypb/Xray-core/common"
     7  	"github.com/xraypb/Xray-core/common/buf"
     8  	"github.com/xraypb/Xray-core/common/crypto"
     9  	"github.com/xraypb/Xray-core/common/net"
    10  	"github.com/xraypb/Xray-core/common/session"
    11  	"github.com/xraypb/Xray-core/common/task"
    12  	"github.com/xraypb/Xray-core/transport"
    13  	"github.com/xraypb/Xray-core/transport/internet"
    14  )
    15  
    16  type Client struct{}
    17  
    18  func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
    19  	return &Client{}, nil
    20  }
    21  
    22  func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
    23  	outbound := session.OutboundFromContext(ctx)
    24  	if outbound == nil || !outbound.Target.IsValid() {
    25  		return newError("unknown destination.")
    26  	}
    27  	dest := outbound.Target
    28  	if dest.Network != net.Network_TCP {
    29  		return newError("not TCP traffic", dest)
    30  	}
    31  
    32  	conn, err := dialer.Dial(ctx, dest)
    33  	if err != nil {
    34  		return newError("failed to dial to ", dest).Base(err).AtWarning()
    35  	}
    36  	defer conn.Close()
    37  
    38  	sc := SessionContextFromContext(ctx)
    39  	auth := NewAuthentication(sc)
    40  	defer putAuthenticationObject(auth)
    41  
    42  	request := func() error {
    43  		encryptor := crypto.NewAesCTRStream(auth.EncodingKey[:], auth.EncodingNonce[:])
    44  
    45  		var header [HeaderSize]byte
    46  		encryptor.XORKeyStream(header[:], auth.Header[:])
    47  		copy(header[:56], auth.Header[:])
    48  
    49  		if _, err := conn.Write(header[:]); err != nil {
    50  			return newError("failed to write auth header").Base(err)
    51  		}
    52  
    53  		connWriter := buf.NewWriter(crypto.NewCryptionWriter(encryptor, conn))
    54  		return buf.Copy(link.Reader, connWriter)
    55  	}
    56  
    57  	response := func() error {
    58  		decryptor := crypto.NewAesCTRStream(auth.DecodingKey[:], auth.DecodingNonce[:])
    59  
    60  		connReader := buf.NewReader(crypto.NewCryptionReader(decryptor, conn))
    61  		return buf.Copy(connReader, link.Writer)
    62  	}
    63  
    64  	responseDoneAndCloseWriter := task.OnSuccess(response, task.Close(link.Writer))
    65  	if err := task.Run(ctx, request, responseDoneAndCloseWriter); err != nil {
    66  		return newError("connection ends").Base(err)
    67  	}
    68  
    69  	return nil
    70  }
    71  
    72  func init() {
    73  	common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
    74  		return NewClient(ctx, config.(*ClientConfig))
    75  	}))
    76  }