package dcs
import (
"context"
"io"
"net"
"github.com/go-faster/errors"
"go.uber.org/multierr"
"github.com/gotd/td/internal/crypto"
"github.com/gotd/td/internal/mtproxy"
"github.com/gotd/td/internal/mtproxy/obfuscator"
"github.com/gotd/td/internal/proto/codec"
"github.com/gotd/td/transport"
)
var _ Resolver = mtProxy {}
type mtProxy struct {
dial DialFunc
protocol protocol
addr , network string
secret mtproxy .Secret
tag [4 ]byte
rand io .Reader
}
func (m mtProxy ) Primary (ctx context .Context , dc int , _ List ) (transport .Conn , error ) {
return m .resolve (ctx , dc )
}
func (m mtProxy ) MediaOnly (ctx context .Context , dc int , _ List ) (transport .Conn , error ) {
if dc > 0 {
dc *= -1
}
return m .resolve (ctx , dc )
}
func (m mtProxy ) CDN (ctx context .Context , dc int , _ List ) (transport .Conn , error ) {
return m .resolve (ctx , dc )
}
func (m mtProxy ) resolve (ctx context .Context , dc int ) (transport .Conn , error ) {
c , err := m .dial (ctx , m .network , m .addr )
if err != nil {
return nil , errors .Wrapf (err , "connect to the MTProxy %q" , m .addr )
}
conn , err := m .handshakeConn (c , dc )
if err != nil {
err = errors .Wrap (err , "handshake" )
return nil , multierr .Combine (err , c .Close ())
}
return conn , nil
}
func (m mtProxy ) handshakeConn (c net .Conn , dc int ) (transport .Conn , error ) {
var obsConn *obfuscator .Conn
switch m .secret .Type {
case mtproxy .Simple , mtproxy .Secured :
obsConn = obfuscator .Obfuscated2 (m .rand , c )
case mtproxy .TLS :
obsConn = obfuscator .FakeTLS (m .rand , c )
default :
return nil , errors .Errorf ("unknown MTProxy secret type: %d" , m .secret .Type )
}
secret := m .secret
if err := obsConn .Handshake (m .tag , dc , secret ); err != nil {
return nil , errors .Wrap (err , "MTProxy handshake" )
}
transportConn , err := m .protocol .Handshake (obsConn )
if err != nil {
return nil , errors .Wrap (err , "transport handshake" )
}
return transportConn , nil
}
type MTProxyOptions struct {
Dial DialFunc
Network string
Rand io .Reader
}
func (m *MTProxyOptions ) setDefaults () {
if m .Dial == nil {
var d net .Dialer
m .Dial = d .DialContext
}
if m .Network == "" {
m .Network = "tcp"
}
if m .Rand == nil {
m .Rand = crypto .DefaultRand ()
}
}
func MTProxy (addr string , secret []byte , opts MTProxyOptions ) (Resolver , error ) {
s , err := mtproxy .ParseSecret (secret )
if err != nil {
return nil , err
}
var cdc codec .Codec = codec .PaddedIntermediate {}
tag := codec .PaddedIntermediateClientStart
if s .Type != mtproxy .TLS {
if c , ok := s .ExpectedCodec (); ok {
cdc = c
tag = [4 ]byte {s .Tag , s .Tag , s .Tag , s .Tag }
}
}
opts .setDefaults ()
return mtProxy {
dial : opts .Dial ,
addr : addr ,
network : opts .Network ,
protocol : transport .NewProtocol (func () transport .Codec { return codec .NoHeader {Codec : cdc } }),
secret : s ,
tag : tag ,
rand : opts .Rand ,
}, nil
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .