Просмотр исходного кода

Support different client connection types

tags/0.9
9seconds 7 лет назад
Родитель
Сommit
588475268a

+ 2
- 1
client/client.go Просмотреть файл

5
 	"net"
5
 	"net"
6
 
6
 
7
 	"github.com/9seconds/mtg/config"
7
 	"github.com/9seconds/mtg/config"
8
+	"github.com/9seconds/mtg/mtproto"
8
 )
9
 )
9
 
10
 
10
 // Init has to initialize client connection based on given config.
11
 // Init has to initialize client connection based on given config.
11
-type Init func(net.Conn, *config.Config) (int16, io.ReadWriteCloser, error)
12
+type Init func(net.Conn, *config.Config) (*mtproto.ConnectionOpts, io.ReadWriteCloser, error)

+ 6
- 5
client/direct.go Просмотреть файл

7
 	"github.com/juju/errors"
7
 	"github.com/juju/errors"
8
 
8
 
9
 	"github.com/9seconds/mtg/config"
9
 	"github.com/9seconds/mtg/config"
10
+	"github.com/9seconds/mtg/mtproto"
10
 	"github.com/9seconds/mtg/obfuscated2"
11
 	"github.com/9seconds/mtg/obfuscated2"
11
 	"github.com/9seconds/mtg/wrappers"
12
 	"github.com/9seconds/mtg/wrappers"
12
 )
13
 )
13
 
14
 
14
 // DirectInit initializes client to access Telegram bypassing middleproxies.
15
 // DirectInit initializes client to access Telegram bypassing middleproxies.
15
-func DirectInit(conn net.Conn, conf *config.Config) (int16, io.ReadWriteCloser, error) {
16
+func DirectInit(conn net.Conn, conf *config.Config) (*mtproto.ConnectionOpts, io.ReadWriteCloser, error) {
16
 	socket := wrappers.NewTimeoutRWC(conn, conf.TimeoutRead, conf.TimeoutWrite)
17
 	socket := wrappers.NewTimeoutRWC(conn, conf.TimeoutRead, conf.TimeoutWrite)
17
 	frame, err := obfuscated2.ExtractFrame(socket)
18
 	frame, err := obfuscated2.ExtractFrame(socket)
18
 	if err != nil {
19
 	if err != nil {
19
-		return 0, nil, errors.Annotate(err, "Cannot extract frame")
20
+		return nil, nil, errors.Annotate(err, "Cannot extract frame")
20
 	}
21
 	}
21
 	defer obfuscated2.ReturnFrame(frame)
22
 	defer obfuscated2.ReturnFrame(frame)
22
 
23
 
23
-	obfs2, dc, err := obfuscated2.ParseObfuscated2ClientFrame(conf.Secret, frame)
24
+	obfs2, connOpts, err := obfuscated2.ParseObfuscated2ClientFrame(conf.Secret, frame)
24
 	if err != nil {
25
 	if err != nil {
25
-		return 0, nil, errors.Annotate(err, "Cannot parse obfuscated frame")
26
+		return nil, nil, errors.Annotate(err, "Cannot parse obfuscated frame")
26
 	}
27
 	}
27
 
28
 
28
 	socket = wrappers.NewStreamCipherRWC(socket, obfs2.Encryptor, obfs2.Decryptor)
29
 	socket = wrappers.NewStreamCipherRWC(socket, obfs2.Encryptor, obfs2.Decryptor)
29
 
30
 
30
-	return dc, socket, nil
31
+	return connOpts, socket, nil
31
 }
32
 }

+ 55
- 0
mtproto/connection_options.go Просмотреть файл

1
+package mtproto
2
+
3
+import (
4
+	"bytes"
5
+
6
+	"github.com/juju/errors"
7
+)
8
+
9
+// ConnectionType is a type of obfuscated2/mtproto connection requested
10
+// by the user.
11
+type ConnectionType uint8
12
+
13
+// ConnectionOpts presents an options, metadata on connection requested
14
+// by the user on handshake.
15
+type ConnectionOpts struct {
16
+	DC             int16
17
+	ConnectionType ConnectionType
18
+}
19
+
20
+// Different connection types which user requests from Telegram.
21
+const (
22
+	ConnectionTypeUnknown ConnectionType = iota
23
+	ConnectionTypeAbridged
24
+	ConnectionTypeIntermediate
25
+)
26
+
27
+// Connection tags for mtproto handshakes.
28
+var (
29
+	ConnectionTagAbridged     = []byte{0xef, 0xef, 0xef, 0xef}
30
+	ConnectionTagIntermediate = []byte{0xee, 0xee, 0xee, 0xee}
31
+)
32
+
33
+// Tag maps connection type to the corresponding handshake tag.
34
+func (t ConnectionType) Tag() ([]byte, error) {
35
+	switch t {
36
+	case ConnectionTypeAbridged:
37
+		return ConnectionTagAbridged, nil
38
+	case ConnectionTypeIntermediate:
39
+		return ConnectionTagIntermediate, nil
40
+	default:
41
+		return nil, errors.Errorf("Unknown connection type %d", t)
42
+	}
43
+}
44
+
45
+// ConnectionTagFromHandshake maps magic bytes to the connection type.
46
+func ConnectionTagFromHandshake(magic []byte) (ConnectionType, error) {
47
+	if bytes.Equal(magic, ConnectionTagIntermediate) {
48
+		return ConnectionTypeIntermediate, nil
49
+	}
50
+	if bytes.Equal(magic, ConnectionTagAbridged) {
51
+		return ConnectionTypeAbridged, nil
52
+	}
53
+
54
+	return ConnectionTypeUnknown, errors.New("Unknown handshake protocol")
55
+}

+ 9
- 9
obfuscated2/frame.go Просмотреть файл

7
 	"io"
7
 	"io"
8
 
8
 
9
 	"github.com/juju/errors"
9
 	"github.com/juju/errors"
10
+
11
+	"github.com/9seconds/mtg/mtproto"
10
 )
12
 )
11
 
13
 
12
 // [frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd]
14
 // [frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd]
22
 	frameOffsetMagic = frameOffsetIV + frameLenMagic
24
 	frameOffsetMagic = frameOffsetIV + frameLenMagic
23
 	frameOffsetDC    = frameOffsetMagic + frameLenDC
25
 	frameOffsetDC    = frameOffsetMagic + frameLenDC
24
 
26
 
25
-	tgMagicByte = byte(239)
26
-
27
 	FrameLen = 64
27
 	FrameLen = 64
28
 )
28
 )
29
 
29
 
30
-var tgMagicBytes = []byte{tgMagicByte, tgMagicByte, tgMagicByte, tgMagicByte}
31
-
32
 // Frame represents handshake frame. Telegram sends 64 bytes of obfuscated2
30
 // Frame represents handshake frame. Telegram sends 64 bytes of obfuscated2
33
 // initialization data first.
31
 // initialization data first.
34
 // https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
32
 // https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
61
 	return
59
 	return
62
 }
60
 }
63
 
61
 
64
-// Valid checks that *decrypted* frame is valid. Only magic bytes are checked.
65
-func (f Frame) Valid() bool {
66
-	return bytes.Equal(f.Magic(), tgMagicBytes)
62
+// ConnectionType identifies connection type of the handshake frame.
63
+func (f Frame) ConnectionType() (mtproto.ConnectionType, error) {
64
+	return mtproto.ConnectionTagFromHandshake(f.Magic())
67
 }
65
 }
68
 
66
 
69
 // Invert inverts frame for extracting encryption keys. Pkease check that link:
67
 // Invert inverts frame for extracting encryption keys. Pkease check that link:
94
 	return frame, nil
92
 	return frame, nil
95
 }
93
 }
96
 
94
 
97
-func generateFrame() *Frame {
95
+func generateFrame(connectionType mtproto.ConnectionType) *Frame {
98
 	frame := MakeFrame()
96
 	frame := MakeFrame()
99
 	data := *frame
97
 	data := *frame
100
 
98
 
116
 			continue
114
 			continue
117
 		}
115
 		}
118
 
116
 
119
-		copy(data.Magic(), tgMagicBytes)
117
+		// error has to be checked before calling this function
118
+		tag, _ := connectionType.Tag() // nolint: errcheck
119
+		copy(data.Magic(), tag)
120
 
120
 
121
 		return frame
121
 		return frame
122
 	}
122
 	}

+ 22
- 5
obfuscated2/frame_test.go Просмотреть файл

2
 
2
 
3
 import (
3
 import (
4
 	"bytes"
4
 	"bytes"
5
+	"strconv"
5
 	"testing"
6
 	"testing"
6
 
7
 
7
 	"github.com/stretchr/testify/assert"
8
 	"github.com/stretchr/testify/assert"
9
+
10
+	"github.com/9seconds/mtg/mtproto"
8
 )
11
 )
9
 
12
 
10
 func TestFrameKey(t *testing.T) {
13
 func TestFrameKey(t *testing.T) {
28
 func TestFrameMagic(t *testing.T) {
31
 func TestFrameMagic(t *testing.T) {
29
 	toCompare := make([]byte, 4)
32
 	toCompare := make([]byte, 4)
30
 	for i := 0; i < 4; i++ {
33
 	for i := 0; i < 4; i++ {
31
-		toCompare[i] = tgMagicByte
34
+		toCompare[i] = 0xee
32
 	}
35
 	}
33
 
36
 
34
 	assert.Equal(t, toCompare, makeFrame().Magic())
37
 	assert.Equal(t, toCompare, makeFrame().Magic())
40
 
43
 
41
 func TestFrameValid(t *testing.T) {
44
 func TestFrameValid(t *testing.T) {
42
 	frame := makeFrame()
45
 	frame := makeFrame()
43
-	assert.True(t, frame.Valid())
46
+	connType, err := frame.ConnectionType()
47
+	assert.Nil(t, err)
48
+	assert.Equal(t, connType, mtproto.ConnectionTypeIntermediate)
44
 
49
 
45
 	frame[8+32+16+2] = byte(3)
50
 	frame[8+32+16+2] = byte(3)
46
-	assert.False(t, frame.Valid())
51
+	_, err = frame.ConnectionType()
52
+	assert.NotNil(t, err)
47
 }
53
 }
48
 
54
 
49
 func TestFrameDoubleInvert(t *testing.T) {
55
 func TestFrameDoubleInvert(t *testing.T) {
66
 }
72
 }
67
 
73
 
68
 func TestFrameGenerateValid(t *testing.T) {
74
 func TestFrameGenerateValid(t *testing.T) {
69
-	assert.True(t, generateFrame().Valid())
75
+	validTests := []mtproto.ConnectionType{
76
+		mtproto.ConnectionTypeIntermediate,
77
+		mtproto.ConnectionTypeAbridged,
78
+	}
79
+	for _, test := range validTests {
80
+		t.Run(strconv.Itoa(int(test)), func(tt *testing.T) {
81
+			frame := generateFrame(test)
82
+			conType, err := frame.ConnectionType()
83
+			assert.Nil(t, err)
84
+			assert.Equal(t, conType, test)
85
+		})
86
+	}
70
 }
87
 }
71
 
88
 
72
 func makeFrame() Frame {
89
 func makeFrame() Frame {
79
 		f[i] = byte(2)
96
 		f[i] = byte(2)
80
 	}
97
 	}
81
 	for i := (8 + 32 + 16); i < (8 + 32 + 16 + 4); i++ {
98
 	for i := (8 + 32 + 16); i < (8 + 32 + 16 + 4); i++ {
82
-		f[i] = tgMagicByte
99
+		f[i] = 0xee
83
 	}
100
 	}
84
 	for i := (8 + 32 + 16 + 4); i < (8 + 32 + 16 + 4 + 2); i++ {
101
 	for i := (8 + 32 + 16 + 4); i < (8 + 32 + 16 + 4 + 2); i++ {
85
 		f[i] = byte(3)
102
 		f[i] = byte(3)

+ 13
- 6
obfuscated2/obfuscated2.go Просмотреть файл

6
 	"crypto/sha256"
6
 	"crypto/sha256"
7
 
7
 
8
 	"github.com/juju/errors"
8
 	"github.com/juju/errors"
9
+
10
+	"github.com/9seconds/mtg/mtproto"
9
 )
11
 )
10
 
12
 
11
 // Obfuscated2 contains AES CTR encryption and decryption streams
13
 // Obfuscated2 contains AES CTR encryption and decryption streams
19
 // details: http://telegra.ph/telegram-blocks-wtf-05-26
21
 // details: http://telegra.ph/telegram-blocks-wtf-05-26
20
 //
22
 //
21
 // Beware, link above is in russian.
23
 // Beware, link above is in russian.
22
-func ParseObfuscated2ClientFrame(secret []byte, frame *Frame) (*Obfuscated2, int16, error) {
24
+func ParseObfuscated2ClientFrame(secret []byte, frame *Frame) (*Obfuscated2, *mtproto.ConnectionOpts, error) {
23
 	decHasher := sha256.New()
25
 	decHasher := sha256.New()
24
 	decHasher.Write(frame.Key()) // nolint: errcheck
26
 	decHasher.Write(frame.Key()) // nolint: errcheck
25
 	decHasher.Write(secret)      // nolint: errcheck
27
 	decHasher.Write(secret)      // nolint: errcheck
34
 	decryptedFrame := MakeFrame()
36
 	decryptedFrame := MakeFrame()
35
 	defer ReturnFrame(decryptedFrame)
37
 	defer ReturnFrame(decryptedFrame)
36
 	decryptor.XORKeyStream(*decryptedFrame, *frame)
38
 	decryptor.XORKeyStream(*decryptedFrame, *frame)
37
-	if !decryptedFrame.Valid() {
38
-		return nil, 0, errors.New("Unknown protocol")
39
+	connType, err := decryptedFrame.ConnectionType()
40
+	if err != nil {
41
+		return nil, nil, errors.Annotate(err, "Unknown protocol")
39
 	}
42
 	}
40
 
43
 
41
 	obfs := &Obfuscated2{
44
 	obfs := &Obfuscated2{
42
 		Decryptor: decryptor,
45
 		Decryptor: decryptor,
43
 		Encryptor: encryptor,
46
 		Encryptor: encryptor,
44
 	}
47
 	}
48
+	connOpts := &mtproto.ConnectionOpts{
49
+		DC:             decryptedFrame.DC(),
50
+		ConnectionType: connType,
51
+	}
45
 
52
 
46
-	return obfs, decryptedFrame.DC(), nil
53
+	return obfs, connOpts, nil
47
 }
54
 }
48
 
55
 
49
 // MakeTelegramObfuscated2Frame creates new handshake frame to send to
56
 // MakeTelegramObfuscated2Frame creates new handshake frame to send to
50
 // Telegram.
57
 // Telegram.
51
 // https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
58
 // https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
52
-func MakeTelegramObfuscated2Frame() (*Obfuscated2, *Frame) {
53
-	frame := generateFrame()
59
+func MakeTelegramObfuscated2Frame(opts *mtproto.ConnectionOpts) (*Obfuscated2, *Frame) {
60
+	frame := generateFrame(opts.ConnectionType)
54
 
61
 
55
 	encryptor := makeStreamCipher(frame.Key(), frame.IV())
62
 	encryptor := makeStreamCipher(frame.Key(), frame.IV())
56
 	decryptorFrame := frame.Invert()
63
 	decryptorFrame := frame.Invert()

+ 22
- 6
obfuscated2/obfuscated2_test.go Просмотреть файл

5
 	"testing"
5
 	"testing"
6
 
6
 
7
 	"github.com/stretchr/testify/assert"
7
 	"github.com/stretchr/testify/assert"
8
+
9
+	"github.com/9seconds/mtg/mtproto"
8
 )
10
 )
9
 
11
 
10
 func TestObfs2TelegramFrameDecrypt(t *testing.T) {
12
 func TestObfs2TelegramFrameDecrypt(t *testing.T) {
11
-	_, frame := MakeTelegramObfuscated2Frame()
13
+	connOpts := &mtproto.ConnectionOpts{
14
+		DC:             1,
15
+		ConnectionType: mtproto.ConnectionTypeIntermediate,
16
+	}
17
+	_, frame := MakeTelegramObfuscated2Frame(connOpts)
12
 	decryptor := makeStreamCipher(frame.Key(), frame.IV())
18
 	decryptor := makeStreamCipher(frame.Key(), frame.IV())
13
 
19
 
14
 	decrypted := make(Frame, FrameLen)
20
 	decrypted := make(Frame, FrameLen)
15
 	decryptor.XORKeyStream(decrypted, *frame)
21
 	decryptor.XORKeyStream(decrypted, *frame)
16
 
22
 
17
-	assert.True(t, decrypted.Valid())
23
+	_, err := decrypted.ConnectionType()
24
+	assert.Nil(t, err)
18
 }
25
 }
19
 
26
 
20
 func TestObfs2TelegramDecryptEncryptDecrypt(t *testing.T) {
27
 func TestObfs2TelegramDecryptEncryptDecrypt(t *testing.T) {
21
-	obfs2, frame := MakeTelegramObfuscated2Frame()
28
+	connOpts := &mtproto.ConnectionOpts{
29
+		DC:             1,
30
+		ConnectionType: mtproto.ConnectionTypeIntermediate,
31
+	}
32
+	obfs2, frame := MakeTelegramObfuscated2Frame(connOpts)
22
 	inverted := frame.Invert()
33
 	inverted := frame.Invert()
23
 	encryptor := makeStreamCipher(inverted.Key(), inverted.IV())
34
 	encryptor := makeStreamCipher(inverted.Key(), inverted.IV())
24
 
35
 
34
 func TestObfs2Full(t *testing.T) {
45
 func TestObfs2Full(t *testing.T) {
35
 	secret := []byte{1, 2, 3, 4, 5}
46
 	secret := []byte{1, 2, 3, 4, 5}
36
 
47
 
37
-	clientFrame := generateFrame()
48
+	clientFrame := generateFrame(mtproto.ConnectionTypeIntermediate)
38
 	clientHasher := sha256.New()
49
 	clientHasher := sha256.New()
39
 	clientHasher.Write(clientFrame.Key())
50
 	clientHasher.Write(clientFrame.Key())
40
 	clientHasher.Write(secret)
51
 	clientHasher.Write(secret)
55
 	clientObfs, _, err := ParseObfuscated2ClientFrame(secret, &encrypted)
66
 	clientObfs, _, err := ParseObfuscated2ClientFrame(secret, &encrypted)
56
 	assert.Nil(t, err)
67
 	assert.Nil(t, err)
57
 
68
 
58
-	tgObfs, tgFrame := MakeTelegramObfuscated2Frame()
69
+	connOpts := &mtproto.ConnectionOpts{
70
+		DC:             1,
71
+		ConnectionType: mtproto.ConnectionTypeIntermediate,
72
+	}
73
+	tgObfs, tgFrame := MakeTelegramObfuscated2Frame(connOpts)
59
 	tgDecryptor := makeStreamCipher(tgFrame.Key(), tgFrame.IV())
74
 	tgDecryptor := makeStreamCipher(tgFrame.Key(), tgFrame.IV())
60
 	decrypted := make(Frame, FrameLen)
75
 	decrypted := make(Frame, FrameLen)
61
 	tgDecryptor.XORKeyStream(decrypted, *tgFrame)
76
 	tgDecryptor.XORKeyStream(decrypted, *tgFrame)
62
-	assert.True(t, decrypted.Valid())
77
+	_, err = decrypted.ConnectionType()
78
+	assert.Nil(t, err)
63
 
79
 
64
 	tgInvertedFrame := tgFrame.Invert()
80
 	tgInvertedFrame := tgFrame.Invert()
65
 	tgEncryptor := makeStreamCipher(tgInvertedFrame.Key(), tgInvertedFrame.IV())
81
 	tgEncryptor := makeStreamCipher(tgInvertedFrame.Key(), tgInvertedFrame.IV())

+ 10
- 9
proxy/server.go Просмотреть файл

12
 
12
 
13
 	"github.com/9seconds/mtg/client"
13
 	"github.com/9seconds/mtg/client"
14
 	"github.com/9seconds/mtg/config"
14
 	"github.com/9seconds/mtg/config"
15
+	"github.com/9seconds/mtg/mtproto"
15
 	"github.com/9seconds/mtg/telegram"
16
 	"github.com/9seconds/mtg/telegram"
16
 	"github.com/9seconds/mtg/wrappers"
17
 	"github.com/9seconds/mtg/wrappers"
17
 )
18
 )
60
 		"socketid", socketID,
61
 		"socketid", socketID,
61
 	)
62
 	)
62
 
63
 
63
-	dc, clientConn, err := s.getClientStream(ctx, cancel, conn, socketID)
64
+	connOpts, clientConn, err := s.getClientStream(ctx, cancel, conn, socketID)
64
 	if err != nil {
65
 	if err != nil {
65
 		s.logger.Warnw("Cannot initialize client connection",
66
 		s.logger.Warnw("Cannot initialize client connection",
66
 			"addr", conn.RemoteAddr().String(),
67
 			"addr", conn.RemoteAddr().String(),
71
 	}
72
 	}
72
 	defer clientConn.Close() // nolint: errcheck
73
 	defer clientConn.Close() // nolint: errcheck
73
 
74
 
74
-	tgConn, err := s.getTelegramStream(ctx, cancel, dc, socketID)
75
+	tgConn, err := s.getTelegramStream(ctx, cancel, connOpts, socketID)
75
 	if err != nil {
76
 	if err != nil {
76
 		s.logger.Warnw("Cannot initialize Telegram connection",
77
 		s.logger.Warnw("Cannot initialize Telegram connection",
77
 			"socketid", socketID,
78
 			"socketid", socketID,
96
 	)
97
 	)
97
 }
98
 }
98
 
99
 
99
-func (s *Server) getClientStream(ctx context.Context, cancel context.CancelFunc, conn net.Conn, socketID string) (int16, io.ReadWriteCloser, error) {
100
-	dc, socket, err := s.clientInit(conn, s.conf)
100
+func (s *Server) getClientStream(ctx context.Context, cancel context.CancelFunc, conn net.Conn, socketID string) (*mtproto.ConnectionOpts, io.ReadWriteCloser, error) {
101
+	connOpts, socket, err := s.clientInit(conn, s.conf)
101
 	if err != nil {
102
 	if err != nil {
102
-		return 0, nil, errors.Annotate(err, "Cannot init client connection")
103
+		return nil, nil, errors.Annotate(err, "Cannot init client connection")
103
 	}
104
 	}
104
 
105
 
105
 	socket = wrappers.NewTrafficRWC(socket, s.stats.addIncomingTraffic, s.stats.addOutgoingTraffic)
106
 	socket = wrappers.NewTrafficRWC(socket, s.stats.addIncomingTraffic, s.stats.addOutgoingTraffic)
106
 	socket = wrappers.NewLogRWC(socket, s.logger, socketID, "client")
107
 	socket = wrappers.NewLogRWC(socket, s.logger, socketID, "client")
107
 	socket = wrappers.NewCtxRWC(ctx, cancel, socket)
108
 	socket = wrappers.NewCtxRWC(ctx, cancel, socket)
108
 
109
 
109
-	return dc, socket, nil
110
+	return connOpts, socket, nil
110
 }
111
 }
111
 
112
 
112
-func (s *Server) getTelegramStream(ctx context.Context, cancel context.CancelFunc, dc int16, socketID string) (io.ReadWriteCloser, error) {
113
-	conn, err := s.tg.Dial(dc)
113
+func (s *Server) getTelegramStream(ctx context.Context, cancel context.CancelFunc, connOpts *mtproto.ConnectionOpts, socketID string) (io.ReadWriteCloser, error) {
114
+	conn, err := s.tg.Dial(connOpts)
114
 	if err != nil {
115
 	if err != nil {
115
 		return nil, errors.Annotate(err, "Cannot connect to Telegram")
116
 		return nil, errors.Annotate(err, "Cannot connect to Telegram")
116
 	}
117
 	}
117
 
118
 
118
 	conn = wrappers.NewTrafficRWC(conn, s.stats.addIncomingTraffic, s.stats.addOutgoingTraffic)
119
 	conn = wrappers.NewTrafficRWC(conn, s.stats.addIncomingTraffic, s.stats.addOutgoingTraffic)
119
-	conn, err = s.tg.Init(conn)
120
+	conn, err = s.tg.Init(connOpts, conn)
120
 	if err != nil {
121
 	if err != nil {
121
 		return nil, errors.Annotate(err, "Cannot handshake Telegram")
122
 		return nil, errors.Annotate(err, "Cannot handshake Telegram")
122
 	}
123
 	}

+ 2
- 2
telegram/dialer.go Просмотреть файл

45
 	return wrappers.NewTimeoutRWC(conn, t.conf.TimeoutRead, t.conf.TimeoutWrite), nil
45
 	return wrappers.NewTimeoutRWC(conn, t.conf.TimeoutRead, t.conf.TimeoutWrite), nil
46
 }
46
 }
47
 
47
 
48
-func newDialer(conf *config.Config) *tgDialer {
49
-	return &tgDialer{
48
+func newDialer(conf *config.Config) tgDialer {
49
+	return tgDialer{
50
 		Dialer: net.Dialer{Timeout: conf.TimeoutRead},
50
 		Dialer: net.Dialer{Timeout: conf.TimeoutRead},
51
 		conf:   conf,
51
 		conf:   conf,
52
 	}
52
 	}

+ 10
- 8
telegram/direct.go Просмотреть файл

6
 	"github.com/juju/errors"
6
 	"github.com/juju/errors"
7
 
7
 
8
 	"github.com/9seconds/mtg/config"
8
 	"github.com/9seconds/mtg/config"
9
+	"github.com/9seconds/mtg/mtproto"
9
 	"github.com/9seconds/mtg/obfuscated2"
10
 	"github.com/9seconds/mtg/obfuscated2"
10
 	"github.com/9seconds/mtg/wrappers"
11
 	"github.com/9seconds/mtg/wrappers"
11
 )
12
 )
31
 	baseTelegram
32
 	baseTelegram
32
 }
33
 }
33
 
34
 
34
-func (t *directTelegram) Dial(dcIdx int16) (io.ReadWriteCloser, error) {
35
-	if dcIdx < 0 {
36
-		dcIdx = -dcIdx
37
-	} else if dcIdx == 0 {
38
-		dcIdx = 1
35
+func (t *directTelegram) Dial(connOpts *mtproto.ConnectionOpts) (io.ReadWriteCloser, error) {
36
+	dc := connOpts.DC
37
+	if dc < 0 {
38
+		dc = -dc
39
+	} else if dc == 0 {
40
+		dc = 1
39
 	}
41
 	}
40
 
42
 
41
-	return t.baseTelegram.Dial(dcIdx - 1)
43
+	return t.baseTelegram.dial(dc - 1)
42
 }
44
 }
43
 
45
 
44
-func (t *directTelegram) Init(conn io.ReadWriteCloser) (io.ReadWriteCloser, error) {
45
-	obfs2, frame := obfuscated2.MakeTelegramObfuscated2Frame()
46
+func (t *directTelegram) Init(connOpts *mtproto.ConnectionOpts, conn io.ReadWriteCloser) (io.ReadWriteCloser, error) {
47
+	obfs2, frame := obfuscated2.MakeTelegramObfuscated2Frame(connOpts)
46
 	defer obfuscated2.ReturnFrame(frame)
48
 	defer obfuscated2.ReturnFrame(frame)
47
 
49
 
48
 	if n, err := conn.Write(*frame); err != nil || n != len(*frame) {
50
 	if n, err := conn.Write(*frame); err != nil || n != len(*frame) {

+ 6
- 4
telegram/telegram.go Просмотреть файл

5
 	"math/rand"
5
 	"math/rand"
6
 
6
 
7
 	"github.com/juju/errors"
7
 	"github.com/juju/errors"
8
+
9
+	"github.com/9seconds/mtg/mtproto"
8
 )
10
 )
9
 
11
 
10
 // Telegram defines an interface to connect to Telegram. This
12
 // Telegram defines an interface to connect to Telegram. This
11
 // encapsulates logic of working with middleproxies or direct
13
 // encapsulates logic of working with middleproxies or direct
12
 // connections.
14
 // connections.
13
 type Telegram interface {
15
 type Telegram interface {
14
-	Dial(int16) (io.ReadWriteCloser, error)
15
-	Init(io.ReadWriteCloser) (io.ReadWriteCloser, error)
16
+	Dial(*mtproto.ConnectionOpts) (io.ReadWriteCloser, error)
17
+	Init(*mtproto.ConnectionOpts, io.ReadWriteCloser) (io.ReadWriteCloser, error)
16
 }
18
 }
17
 
19
 
18
 type baseTelegram struct {
20
 type baseTelegram struct {
19
-	dialer *tgDialer
21
+	dialer tgDialer
20
 
22
 
21
 	v4Addresses map[int16][]string
23
 	v4Addresses map[int16][]string
22
 	v6Addresses map[int16][]string
24
 	v6Addresses map[int16][]string
23
 }
25
 }
24
 
26
 
25
-func (b *baseTelegram) Dial(dcIdx int16) (io.ReadWriteCloser, error) {
27
+func (b *baseTelegram) dial(dcIdx int16) (io.ReadWriteCloser, error) {
26
 	addrs := make([]string, 2)
28
 	addrs := make([]string, 2)
27
 	if addr, ok := b.v6Addresses[dcIdx]; ok && len(addr) > 0 {
29
 	if addr, ok := b.v6Addresses[dcIdx]; ok && len(addr) > 0 {
28
 		addrs = append(addrs, addr[rand.Intn(len(addr))])
30
 		addrs = append(addrs, addr[rand.Intn(len(addr))])

Загрузка…
Отмена
Сохранить