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

Move telegram to separate module

tags/0.9
9seconds 7 лет назад
Родитель
Сommit
5a169b5026
6 измененных файлов: 163 добавлений и 91 удалений
  1. 1
    7
      obfuscated2/frame.go
  2. 12
    11
      proxy/server.go
  3. 0
    73
      proxy/telegram.go
  4. 53
    0
      telegram/dialer.go
  5. 59
    0
      telegram/direct.go
  6. 38
    0
      telegram/telegram.go

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

@@ -58,13 +58,7 @@ func (f Frame) DC() (n int16) {
58 58
 		n = 1
59 59
 	}
60 60
 
61
-	if n < 0 {
62
-		n = -n
63
-	} else if n == 0 {
64
-		n = 1
65
-	}
66
-
67
-	return n - 1
61
+	return
68 62
 }
69 63
 
70 64
 // Valid checks that *decrypted* frame is valid. Only magic bytes are checked.

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

@@ -12,6 +12,7 @@ import (
12 12
 
13 13
 	"github.com/9seconds/mtg/config"
14 14
 	"github.com/9seconds/mtg/obfuscated2"
15
+	"github.com/9seconds/mtg/telegram"
15 16
 	"github.com/9seconds/mtg/wrappers"
16 17
 )
17 18
 
@@ -20,6 +21,7 @@ type Server struct {
20 21
 	conf   *config.Config
21 22
 	logger *zap.SugaredLogger
22 23
 	stats  *Stats
24
+	tg     telegram.Telegram
23 25
 }
24 26
 
25 27
 // Serve does MTPROTO proxying.
@@ -118,23 +120,21 @@ func (s *Server) getClientStream(ctx context.Context, cancel context.CancelFunc,
118 120
 }
119 121
 
120 122
 func (s *Server) getTelegramStream(ctx context.Context, cancel context.CancelFunc, dc int16, socketID string) (io.ReadWriteCloser, error) {
121
-	socket, err := dialToTelegram(dc, s.conf.TimeoutRead)
123
+	conn, err := s.tg.Dial(dc)
122 124
 	if err != nil {
123
-		return nil, errors.Annotate(err, "Cannot dial")
125
+		return nil, errors.Annotate(err, "Cannot connect to Telegram")
124 126
 	}
125
-	wConn := wrappers.NewTimeoutRWC(socket, s.conf.TimeoutRead, s.conf.TimeoutWrite)
126
-	wConn = wrappers.NewTrafficRWC(wConn, s.stats.addIncomingTraffic, s.stats.addOutgoingTraffic)
127 127
 
128
-	obfs2, frame := obfuscated2.MakeTelegramObfuscated2Frame()
129
-	if n, err := socket.Write(frame); err != nil || n != len(frame) {
130
-		return nil, errors.Annotate(err, "Cannot write hadnshake frame")
128
+	conn = wrappers.NewTrafficRWC(conn, s.stats.addIncomingTraffic, s.stats.addOutgoingTraffic)
129
+	conn, err = s.tg.Init(conn)
130
+	if err != nil {
131
+		return nil, errors.Annotate(err, "Cannot handshake Telegram")
131 132
 	}
132 133
 
133
-	wConn = wrappers.NewLogRWC(wConn, s.logger, socketID, "telegram")
134
-	wConn = wrappers.NewStreamCipherRWC(wConn, obfs2.Encryptor, obfs2.Decryptor)
135
-	wConn = wrappers.NewCtxRWC(ctx, cancel, wConn)
134
+	conn = wrappers.NewLogRWC(conn, s.logger, socketID, "telegram")
135
+	conn = wrappers.NewCtxRWC(ctx, cancel, conn)
136 136
 
137
-	return wConn, nil
137
+	return conn, nil
138 138
 }
139 139
 
140 140
 // NewServer creates new instance of MTPROTO proxy.
@@ -143,5 +143,6 @@ func NewServer(conf *config.Config, logger *zap.SugaredLogger, stat *Stats) *Ser
143 143
 		conf:   conf,
144 144
 		logger: logger,
145 145
 		stats:  stat,
146
+		tg:     telegram.NewDirectTelegram(conf),
146 147
 	}
147 148
 }

+ 0
- 73
proxy/telegram.go Просмотреть файл

@@ -1,73 +0,0 @@
1
-package proxy
2
-
3
-import (
4
-	"net"
5
-	"time"
6
-
7
-	"github.com/juju/errors"
8
-)
9
-
10
-// TelegramAddress presents a pair of v4 and v6 addresses. This pairization
11
-// is required because we want to use DC indexes.
12
-type TelegramAddress struct {
13
-	v4 string
14
-	v6 string
15
-}
16
-
17
-// IPv4 returns v4 address.
18
-func (t *TelegramAddress) IPv4() string {
19
-	return net.JoinHostPort(t.v4, telegramPort)
20
-}
21
-
22
-// IPv6 returns v4 address.
23
-func (t *TelegramAddress) IPv6() string {
24
-	return net.JoinHostPort(t.v6, telegramPort)
25
-}
26
-
27
-// TelegramAddresses is a list of all known Telegram addresses for DC indexes.
28
-var TelegramAddresses = []TelegramAddress{
29
-	TelegramAddress{v4: "149.154.175.50", v6: "2001:b28:f23d:f001::a"},
30
-	TelegramAddress{v4: "149.154.167.51", v6: "2001:67c:04e8:f002::a"},
31
-	TelegramAddress{v4: "149.154.175.100", v6: "2001:b28:f23d:f003::a"},
32
-	TelegramAddress{v4: "149.154.167.91", v6: "2001:67c:04e8:f004::a"},
33
-	TelegramAddress{v4: "149.154.171.5", v6: "2001:b28:f23f:f005::a"},
34
-}
35
-
36
-const telegramPort = "443"
37
-
38
-const telegramKeepAlive = 30 * time.Second
39
-
40
-func dialToTelegram(dcIdx int16, timeout time.Duration) (net.Conn, error) {
41
-	if dcIdx < 0 || dcIdx >= 5 {
42
-		return nil, errors.New("Incorrect DC IDX")
43
-	}
44
-
45
-	conn, err := doDial(dcIdx, timeout)
46
-	if err != nil {
47
-		return nil, errors.Annotate(err, "Cannot dial")
48
-	}
49
-
50
-	if err := conn.SetKeepAlive(true); err != nil {
51
-		return nil, errors.Annotate(err, "Cannot establish keepalive connection")
52
-	}
53
-	if err := conn.SetKeepAlivePeriod(telegramKeepAlive); err != nil {
54
-		return nil, errors.Annotate(err, "Cannot set keepalive timeout")
55
-	}
56
-
57
-	return conn, nil
58
-}
59
-
60
-func doDial(dcIdx int16, timeout time.Duration) (*net.TCPConn, error) {
61
-	dialer := net.Dialer{Timeout: timeout}
62
-	addr := TelegramAddresses[dcIdx]
63
-
64
-	if conn, err := dialer.Dial("tcp", addr.IPv6()); err == nil {
65
-		return conn.(*net.TCPConn), nil
66
-	}
67
-
68
-	conn, err := dialer.Dial("tcp", addr.IPv4())
69
-	if err == nil {
70
-		return conn.(*net.TCPConn), nil
71
-	}
72
-	return nil, err
73
-}

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

@@ -0,0 +1,53 @@
1
+package telegram
2
+
3
+import (
4
+	"io"
5
+	"net"
6
+	"time"
7
+
8
+	"github.com/juju/errors"
9
+
10
+	"github.com/9seconds/mtg/config"
11
+	"github.com/9seconds/mtg/wrappers"
12
+)
13
+
14
+const telegramKeepAlive = 30 * time.Second
15
+
16
+type tgDialer struct {
17
+	net.Dialer
18
+
19
+	conf *config.Config
20
+}
21
+
22
+func (t *tgDialer) dial(addr string) (net.Conn, error) {
23
+	connRaw, err := t.Dialer.Dial("tcp", addr)
24
+	if err != nil {
25
+		return nil, errors.Annotate(err, "Cannot connect to Telegram")
26
+	}
27
+	conn := connRaw.(*net.TCPConn)
28
+
29
+	if err = conn.SetKeepAlive(true); err != nil {
30
+		return nil, errors.Annotate(err, "Cannot establish keepalive connection")
31
+	}
32
+	if err = conn.SetKeepAlivePeriod(telegramKeepAlive); err != nil {
33
+		return nil, errors.Annotate(err, "Cannot set keepalive timeout")
34
+	}
35
+
36
+	return conn, nil
37
+}
38
+
39
+func (t *tgDialer) dialRWC(addr string) (io.ReadWriteCloser, error) {
40
+	conn, err := t.dial(addr)
41
+	if err != nil {
42
+		return nil, err
43
+	}
44
+
45
+	return wrappers.NewTimeoutRWC(conn, t.conf.TimeoutRead, t.conf.TimeoutWrite), nil
46
+}
47
+
48
+func newDialer(conf *config.Config) *tgDialer {
49
+	return &tgDialer{
50
+		Dialer: net.Dialer{Timeout: conf.TimeoutRead},
51
+		conf:   conf,
52
+	}
53
+}

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

@@ -0,0 +1,59 @@
1
+package telegram
2
+
3
+import (
4
+	"io"
5
+
6
+	"github.com/juju/errors"
7
+
8
+	"github.com/9seconds/mtg/config"
9
+	"github.com/9seconds/mtg/obfuscated2"
10
+	"github.com/9seconds/mtg/wrappers"
11
+)
12
+
13
+var (
14
+	directV4Addresses = map[int16][]string{
15
+		0: []string{"149.154.175.50:443"},
16
+		1: []string{"149.154.167.51:443"},
17
+		2: []string{"149.154.175.100:443"},
18
+		3: []string{"149.154.167.91:443"},
19
+		4: []string{"149.154.171.5:443"},
20
+	}
21
+	directV6Addresses = map[int16][]string{
22
+		0: []string{"[2001:b28:f23d:f001::a]:443"},
23
+		1: []string{"[2001:67c:04e8:f002::a]:443"},
24
+		2: []string{"[2001:b28:f23d:f003::a]:443"},
25
+		3: []string{"[2001:67c:04e8:f004::a]:443"},
26
+		4: []string{"[2001:b28:f23f:f005::a]:443"},
27
+	}
28
+)
29
+
30
+type directTelegram struct {
31
+	baseTelegram
32
+}
33
+
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
39
+	}
40
+
41
+	return t.baseTelegram.Dial(dcIdx - 1)
42
+}
43
+
44
+func (t *directTelegram) Init(conn io.ReadWriteCloser) (io.ReadWriteCloser, error) {
45
+	obfs2, frame := obfuscated2.MakeTelegramObfuscated2Frame()
46
+	if n, err := conn.Write(frame); err != nil || n != len(frame) {
47
+		return nil, errors.Annotate(err, "Cannot write hadnshake frame")
48
+	}
49
+
50
+	return wrappers.NewStreamCipherRWC(conn, obfs2.Encryptor, obfs2.Decryptor), nil
51
+}
52
+
53
+func NewDirectTelegram(conf *config.Config) Telegram {
54
+	return &directTelegram{baseTelegram{
55
+		dialer:      newDialer(conf),
56
+		v4Addresses: directV4Addresses,
57
+		v6Addresses: directV6Addresses,
58
+	}}
59
+}

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

@@ -0,0 +1,38 @@
1
+package telegram
2
+
3
+import (
4
+	"io"
5
+	"math/rand"
6
+
7
+	"github.com/juju/errors"
8
+)
9
+
10
+type Telegram interface {
11
+	Dial(int16) (io.ReadWriteCloser, error)
12
+	Init(io.ReadWriteCloser) (io.ReadWriteCloser, error)
13
+}
14
+
15
+type baseTelegram struct {
16
+	dialer *tgDialer
17
+
18
+	v4Addresses map[int16][]string
19
+	v6Addresses map[int16][]string
20
+}
21
+
22
+func (b *baseTelegram) Dial(dcIdx int16) (io.ReadWriteCloser, error) {
23
+	addrs := make([]string, 2)
24
+	if addr, ok := b.v6Addresses[dcIdx]; ok && len(addr) > 0 {
25
+		addrs = append(addrs, addr[rand.Intn(len(addr))])
26
+	}
27
+	if addr, ok := b.v4Addresses[dcIdx]; ok && len(addr) > 0 {
28
+		addrs = append(addrs, addr[rand.Intn(len(addr))])
29
+	}
30
+
31
+	for _, addr := range addrs {
32
+		if conn, err := b.dialer.dialRWC(addr); err == nil {
33
+			return conn, err
34
+		}
35
+	}
36
+
37
+	return nil, errors.New("Cannot connect to Telegram")
38
+}

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