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

Remove obsolete files

tags/1.0^2
9seconds 6 лет назад
Родитель
Сommit
d10729490d
46 измененных файлов: 0 добавлений и 3847 удалений
  1. 0
    37
      _antireplay/cache.go
  2. 0
    9
      _antireplay/hasher.go
  3. 0
    15
      _client/client.go
  4. 0
    63
      _client/direct.go
  5. 0
    42
      _client/middle.go
  6. 0
    224
      _config/config.go
  7. 0
    52
      _config/global_ips.go
  8. 0
    58
      _config/urls.go
  9. 0
    87
      _mtproto/connection_options.go
  10. 0
    26
      _mtproto/rpc/handshake_request.go
  11. 0
    55
      _mtproto/rpc/handshake_response.go
  12. 0
    52
      _mtproto/rpc/nonce_request.go
  13. 0
    60
      _mtproto/rpc/nonce_response.go
  14. 0
    59
      _mtproto/rpc/proxy_flags.go
  15. 0
    105
      _mtproto/rpc/proxy_request.go
  16. 0
    28
      _mtproto/rpc/rpc.go
  17. 0
    121
      _obfuscated2/frame.go
  18. 0
    106
      _obfuscated2/frame_test.go
  19. 0
    81
      _obfuscated2/obfuscated2.go
  20. 0
    97
      _obfuscated2/obfuscated2_test.go
  21. 0
    178
      _proxy/proxy.go
  22. 0
    76
      _stats/channels.go
  23. 0
    28
      _stats/init.go
  24. 0
    91
      _stats/prometheus.go
  25. 0
    40
      _stats/server.go
  26. 0
    175
      _stats/stats.go
  27. 0
    77
      _stats/statsd.go
  28. 0
    52
      _telegram/dialer.go
  29. 0
    79
      _telegram/direct.go
  30. 0
    139
      _telegram/middle.go
  31. 0
    191
      _telegram/middle_caller.go
  32. 0
    68
      _telegram/telegram.go
  33. 0
    21
      _utils/read_current_data.go
  34. 0
    15
      _utils/reverse_bytes.go
  35. 0
    15
      _utils/uint24.go
  36. 0
    99
      _wrappers/blockcipher.go
  37. 0
    154
      _wrappers/conn.go
  38. 0
    159
      _wrappers/mtproto_abridged.go
  39. 0
    98
      _wrappers/mtproto_cipher.go
  40. 0
    161
      _wrappers/mtproto_frame.go
  41. 0
    117
      _wrappers/mtproto_intermediate.go
  42. 0
    74
      _wrappers/mtproto_intermediate_secure.go
  43. 0
    165
      _wrappers/mtproto_proxy.go
  44. 0
    73
      _wrappers/streamcipher.go
  45. 0
    14
      _wrappers/streamcipher_pool.go
  46. 0
    111
      _wrappers/wrap.go

+ 0
- 37
_antireplay/cache.go Просмотреть файл

@@ -1,37 +0,0 @@
1
-package antireplay
2
-
3
-import (
4
-	"github.com/allegro/bigcache"
5
-	"github.com/juju/errors"
6
-
7
-	"github.com/9seconds/mtg/config"
8
-)
9
-
10
-// Cache defines storage for obfuscated2 handshake frames.
11
-type Cache struct {
12
-	cache *bigcache.BigCache
13
-}
14
-
15
-func (a Cache) Add(frame []byte) {
16
-	a.cache.Set(string(frame), nil) // nolint: errcheck
17
-}
18
-
19
-func (a Cache) Has(frame []byte) bool {
20
-	_, err := a.cache.Get(string(frame))
21
-
22
-	return err == nil
23
-}
24
-
25
-func NewCache(config *config.Config) (Cache, error) {
26
-	cache, err := bigcache.NewBigCache(bigcache.Config{
27
-		Shards:           1024,
28
-		LifeWindow:       config.AntiReplayEvictionTime,
29
-		Hasher:           hasher{},
30
-		HardMaxCacheSize: config.AntiReplayMaxSize,
31
-	})
32
-	if err != nil {
33
-		return Cache{}, errors.Annotate(err, "Cannot make cache")
34
-	}
35
-
36
-	return Cache{cache}, nil
37
-}

+ 0
- 9
_antireplay/hasher.go Просмотреть файл

@@ -1,9 +0,0 @@
1
-package antireplay
2
-
3
-import "github.com/cespare/xxhash"
4
-
5
-type hasher struct{}
6
-
7
-func (h hasher) Sum64(value string) uint64 {
8
-	return xxhash.Sum64String(value)
9
-}

+ 0
- 15
_client/client.go Просмотреть файл

@@ -1,15 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"context"
5
-	"net"
6
-
7
-	"github.com/9seconds/mtg/antireplay"
8
-	"github.com/9seconds/mtg/config"
9
-	"github.com/9seconds/mtg/mtproto"
10
-	"github.com/9seconds/mtg/wrappers"
11
-)
12
-
13
-// Init defines common method for initializing client connections.
14
-type Init func(context.Context, context.CancelFunc, net.Conn, string,
15
-	antireplay.Cache, *config.Config) (wrappers.Wrap, *mtproto.ConnectionOpts, error)

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

@@ -1,63 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"context"
5
-	"net"
6
-	"time"
7
-
8
-	"github.com/juju/errors"
9
-
10
-	"github.com/9seconds/mtg/antireplay"
11
-	"github.com/9seconds/mtg/config"
12
-	"github.com/9seconds/mtg/mtproto"
13
-	"github.com/9seconds/mtg/obfuscated2"
14
-	"github.com/9seconds/mtg/wrappers"
15
-)
16
-
17
-const handshakeTimeout = 10 * time.Second
18
-
19
-// DirectInit initializes client connection for proxy which connects to
20
-// Telegram directly.
21
-func DirectInit(ctx context.Context, cancel context.CancelFunc, socket net.Conn,
22
-	connID string, antiReplayCache antireplay.Cache,
23
-	conf *config.Config) (wrappers.Wrap, *mtproto.ConnectionOpts, error) {
24
-	tcpSocket := socket.(*net.TCPConn)
25
-	if err := tcpSocket.SetNoDelay(false); err != nil {
26
-		return nil, nil, errors.Annotate(err, "Cannot disable NO_DELAY to client socket")
27
-	}
28
-	if err := tcpSocket.SetReadBuffer(conf.ReadBufferSize); err != nil {
29
-		return nil, nil, errors.Annotate(err, "Cannot set read buffer size of client socket")
30
-	}
31
-	if err := tcpSocket.SetWriteBuffer(conf.WriteBufferSize); err != nil {
32
-		return nil, nil, errors.Annotate(err, "Cannot set write buffer size of client socket")
33
-	}
34
-
35
-	socket.SetReadDeadline(time.Now().Add(handshakeTimeout)) // nolint: errcheck, gosec
36
-	frame, err := obfuscated2.ExtractFrame(socket)
37
-	if err != nil {
38
-		return nil, nil, errors.Annotate(err, "Cannot extract frame")
39
-	}
40
-	socket.SetReadDeadline(time.Time{}) // nolint: errcheck, gosec
41
-
42
-	conn := wrappers.NewConn(ctx, cancel, socket, connID, wrappers.ConnPurposeClient, conf.PublicIPv4, conf.PublicIPv6)
43
-	obfs2, connOpts, err := obfuscated2.ParseObfuscated2ClientFrame(conf.Secret, frame)
44
-	if err != nil {
45
-		return nil, nil, errors.Annotate(err, "Cannot parse obfuscated frame")
46
-	}
47
-
48
-	var replayPart = []byte(frame)
49
-
50
-	if antiReplayCache.Has(replayPart[4:60]) {
51
-		return nil, nil, errors.New("Replay attack is detected")
52
-	}
53
-	antiReplayCache.Add(replayPart[4:60])
54
-
55
-	connOpts.ConnectionProto = mtproto.ConnectionProtocolAny
56
-	connOpts.ClientAddr = conn.RemoteAddr()
57
-
58
-	conn = wrappers.NewStreamCipher(conn, obfs2.Encryptor, obfs2.Decryptor)
59
-
60
-	conn.Logger().Infow("Client connection initialized")
61
-
62
-	return conn, connOpts, nil
63
-}

+ 0
- 42
_client/middle.go Просмотреть файл

@@ -1,42 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"context"
5
-	"net"
6
-
7
-	"github.com/9seconds/mtg/antireplay"
8
-	"github.com/9seconds/mtg/config"
9
-	"github.com/9seconds/mtg/mtproto"
10
-	"github.com/9seconds/mtg/wrappers"
11
-)
12
-
13
-// MiddleInit initializes client connection for proxy which has to
14
-// support promoted channels, connect to Telegram middle proxies etc.
15
-func MiddleInit(ctx context.Context, cancel context.CancelFunc, socket net.Conn,
16
-	connID string, antiReplayCache antireplay.Cache,
17
-	conf *config.Config) (wrappers.Wrap, *mtproto.ConnectionOpts, error) {
18
-	conn, opts, err := DirectInit(ctx, cancel, socket, connID, antiReplayCache, conf)
19
-	if err != nil {
20
-		return nil, nil, err
21
-	}
22
-	connStream := conn.(wrappers.StreamReadWriteCloser)
23
-
24
-	var newConn wrappers.PacketReadWriteCloser
25
-	switch opts.ConnectionType {
26
-	case mtproto.ConnectionTypeAbridged:
27
-		newConn = wrappers.NewMTProtoAbridged(connStream, opts)
28
-	case mtproto.ConnectionTypeIntermediate:
29
-		newConn = wrappers.NewMTProtoIntermediate(connStream, opts)
30
-	case mtproto.ConnectionTypeSecure:
31
-		newConn = wrappers.NewMTProtoIntermediateSecure(connStream, opts)
32
-	default:
33
-		panic("Unknown connection type")
34
-	}
35
-
36
-	opts.ConnectionProto = mtproto.ConnectionProtocolIPv4
37
-	if socket.LocalAddr().(*net.TCPAddr).IP.To4() == nil {
38
-		opts.ConnectionProto = mtproto.ConnectionProtocolIPv6
39
-	}
40
-
41
-	return newConn, opts, err
42
-}

+ 0
- 224
_config/config.go Просмотреть файл

@@ -1,224 +0,0 @@
1
-package config
2
-
3
-import (
4
-	"bytes"
5
-	"encoding/hex"
6
-	"fmt"
7
-	"net"
8
-	"strconv"
9
-	"time"
10
-
11
-	"github.com/juju/errors"
12
-	statsd "gopkg.in/alexcesaro/statsd.v2"
13
-)
14
-
15
-// Config represents common configuration of mtg.
16
-type Config struct {
17
-	Debug      bool
18
-	Verbose    bool
19
-	SecureMode bool
20
-	SecureOnly bool
21
-
22
-	ReadBufferSize  int
23
-	WriteBufferSize int
24
-
25
-	BindPort       uint16
26
-	PublicIPv4Port uint16
27
-	PublicIPv6Port uint16
28
-	StatsPort      uint16
29
-
30
-	BindIP     net.IP
31
-	PublicIPv4 net.IP
32
-	PublicIPv6 net.IP
33
-	StatsIP    net.IP
34
-
35
-	AntiReplayMaxSize      int
36
-	AntiReplayEvictionTime time.Duration
37
-
38
-	StatsD struct {
39
-		Addr       net.Addr
40
-		Prefix     string
41
-		Tags       map[string]string
42
-		TagsFormat statsd.TagFormat
43
-		Enabled    bool
44
-	}
45
-	Prometheus struct {
46
-		Prefix string
47
-	}
48
-
49
-	Secret []byte
50
-	AdTag  []byte
51
-}
52
-
53
-// URLs contains links to the proxy (tg://, t.me) and their QR codes.
54
-type URLs struct {
55
-	TG        string `json:"tg_url"`
56
-	TMe       string `json:"tme_url"`
57
-	TGQRCode  string `json:"tg_qrcode"`
58
-	TMeQRCode string `json:"tme_qrcode"`
59
-}
60
-
61
-// IPURLs contains links to both ipv4 and ipv6 of the proxy.
62
-type IPURLs struct {
63
-	IPv4      URLs   `json:"ipv4"`
64
-	IPv6      URLs   `json:"ipv6"`
65
-	BotSecret string `json:"secret_for_mtproxybot"`
66
-}
67
-
68
-// BindAddr returns connection for this server to bind to.
69
-func (c *Config) BindAddr() string {
70
-	return getAddr(c.BindIP, c.BindPort)
71
-}
72
-
73
-// StatAddr returns connection string to the stats API.
74
-func (c *Config) StatAddr() string {
75
-	return getAddr(c.StatsIP, c.StatsPort)
76
-}
77
-
78
-// UseMiddleProxy defines if this proxy has to connect middle proxies
79
-// which supports promoted channels or directly access Telegram.
80
-func (c *Config) UseMiddleProxy() bool {
81
-	return len(c.AdTag) > 0
82
-}
83
-
84
-// BotSecretString returns secret string which should work with MTProxybot.
85
-func (c *Config) BotSecretString() string {
86
-	return hex.EncodeToString(c.Secret)
87
-}
88
-
89
-// SecretString returns a secret in a form entered on the start of the
90
-// application.
91
-func (c *Config) SecretString() string {
92
-	secret := c.BotSecretString()
93
-	if c.SecureMode {
94
-		return "dd" + secret
95
-	}
96
-	return secret
97
-}
98
-
99
-// GetURLs returns configured IPURLs instance with links to this server.
100
-func (c *Config) GetURLs() IPURLs {
101
-	urls := IPURLs{}
102
-	secret := c.SecretString()
103
-	if c.PublicIPv4 != nil {
104
-		urls.IPv4 = getURLs(c.PublicIPv4, c.PublicIPv4Port, secret)
105
-	}
106
-	if c.PublicIPv6 != nil {
107
-		urls.IPv6 = getURLs(c.PublicIPv6, c.PublicIPv6Port, secret)
108
-	}
109
-	urls.BotSecret = c.BotSecretString()
110
-
111
-	return urls
112
-}
113
-
114
-func getAddr(host fmt.Stringer, port uint16) string {
115
-	return net.JoinHostPort(host.String(), strconv.Itoa(int(port)))
116
-}
117
-
118
-// NewConfig returns new configuration. If required, it manages and
119
-// fetches data from external sources. Parameters passed to this
120
-// function, should come from command line arguments.
121
-func NewConfig(debug, verbose bool, // nolint: gocyclo
122
-	writeBufferSize, readBufferSize uint32,
123
-	bindIP, publicIPv4, publicIPv6, statsIP net.IP,
124
-	bindPort, publicIPv4Port, publicIPv6Port, statsPort, statsdPort uint16,
125
-	statsdIP, statsdNetwork, statsdPrefix, statsdTagsFormat string,
126
-	statsdTags map[string]string, prometheusPrefix string,
127
-	secureOnly bool,
128
-	antiReplayMaxSize int, antiReplayEvictionTime time.Duration,
129
-	secret, adtag []byte) (*Config, error) {
130
-	secureMode := secureOnly
131
-	if bytes.HasPrefix(secret, []byte{0xdd}) && len(secret) == 17 {
132
-		secureMode = true
133
-		secret = bytes.TrimPrefix(secret, []byte{0xdd})
134
-	} else if len(secret) != 16 {
135
-		return nil, errors.New("Telegram demands secret of length 32")
136
-	}
137
-
138
-	var err error
139
-	if publicIPv4 == nil {
140
-		publicIPv4, err = getGlobalIPv4()
141
-		if err != nil {
142
-			publicIPv4 = nil
143
-		} else if publicIPv4.To4() == nil {
144
-			return nil, errors.Errorf("IP %s is not IPv4", publicIPv4.String())
145
-		}
146
-	}
147
-	if publicIPv4Port == 0 {
148
-		publicIPv4Port = bindPort
149
-	}
150
-
151
-	if publicIPv6 == nil {
152
-		publicIPv6, err = getGlobalIPv6()
153
-		if err != nil {
154
-			publicIPv6 = nil
155
-		} else if publicIPv6.To4() != nil {
156
-			return nil, errors.Errorf("IP %s is not IPv6", publicIPv6.String())
157
-		}
158
-	}
159
-	if publicIPv6Port == 0 {
160
-		publicIPv6Port = bindPort
161
-	}
162
-
163
-	if statsIP == nil {
164
-		statsIP = publicIPv4
165
-	}
166
-
167
-	conf := &Config{
168
-		Debug:                  debug,
169
-		Verbose:                verbose,
170
-		SecureOnly:             secureOnly,
171
-		BindIP:                 bindIP,
172
-		BindPort:               bindPort,
173
-		PublicIPv4:             publicIPv4,
174
-		PublicIPv4Port:         publicIPv4Port,
175
-		PublicIPv6:             publicIPv6,
176
-		PublicIPv6Port:         publicIPv6Port,
177
-		StatsIP:                statsIP,
178
-		StatsPort:              statsPort,
179
-		Secret:                 secret,
180
-		AdTag:                  adtag,
181
-		SecureMode:             secureMode,
182
-		ReadBufferSize:         int(readBufferSize),
183
-		WriteBufferSize:        int(writeBufferSize),
184
-		AntiReplayMaxSize:      antiReplayMaxSize,
185
-		AntiReplayEvictionTime: antiReplayEvictionTime,
186
-	}
187
-	conf.Prometheus.Prefix = prometheusPrefix
188
-
189
-	if statsdIP != "" {
190
-		conf.StatsD.Enabled = true
191
-		conf.StatsD.Prefix = statsdPrefix
192
-		conf.StatsD.Tags = statsdTags
193
-
194
-		var (
195
-			addr net.Addr
196
-			err  error
197
-		)
198
-		hostPort := net.JoinHostPort(statsdIP, strconv.Itoa(int(statsdPort)))
199
-		switch statsdNetwork {
200
-		case "tcp":
201
-			addr, err = net.ResolveTCPAddr("tcp", hostPort)
202
-		case "udp":
203
-			addr, err = net.ResolveUDPAddr("udp", hostPort)
204
-		default:
205
-			err = errors.Errorf("Unknown network %s", statsdNetwork)
206
-		}
207
-		if err != nil {
208
-			return nil, errors.Annotate(err, "Cannot resolve statsd address")
209
-		}
210
-		conf.StatsD.Addr = addr
211
-
212
-		switch statsdTagsFormat {
213
-		case "datadog":
214
-			conf.StatsD.TagsFormat = statsd.Datadog
215
-		case "influxdb":
216
-			conf.StatsD.TagsFormat = statsd.InfluxDB
217
-		case "":
218
-		default:
219
-			return nil, errors.Errorf("Unknown tags format %s", statsdTagsFormat)
220
-		}
221
-	}
222
-
223
-	return conf, nil
224
-}

+ 0
- 52
_config/global_ips.go Просмотреть файл

@@ -1,52 +0,0 @@
1
-package config
2
-
3
-import (
4
-	"context"
5
-	"io/ioutil"
6
-	"net"
7
-	"net/http"
8
-	"strings"
9
-
10
-	"github.com/juju/errors"
11
-)
12
-
13
-const ifconfigAddress = "https://ifconfig.co/ip"
14
-
15
-func getGlobalIPv4() (net.IP, error) {
16
-	return fetchIP("tcp4")
17
-}
18
-
19
-func getGlobalIPv6() (net.IP, error) {
20
-	return fetchIP("tcp6")
21
-}
22
-
23
-func fetchIP(network string) (net.IP, error) {
24
-	dialer := &net.Dialer{FallbackDelay: -1}
25
-	client := &http.Client{
26
-		Jar: nil,
27
-		Transport: &http.Transport{
28
-			DialContext: func(ctx context.Context, _, addr string) (net.Conn, error) {
29
-				return dialer.DialContext(ctx, network, addr)
30
-			},
31
-		},
32
-	}
33
-
34
-	resp, err := client.Get(ifconfigAddress)
35
-	if err != nil {
36
-		return nil, err
37
-	}
38
-	defer resp.Body.Close() // nolint: errcheck
39
-
40
-	respDataBytes, err := ioutil.ReadAll(resp.Body)
41
-	if err != nil {
42
-		return nil, err
43
-	}
44
-	respData := strings.TrimSpace(string(respDataBytes))
45
-
46
-	ip := net.ParseIP(respData)
47
-	if ip == nil {
48
-		return nil, errors.Errorf("ifconfig.co returns incorrect IP %s", respData)
49
-	}
50
-
51
-	return ip, nil
52
-}

+ 0
- 58
_config/urls.go Просмотреть файл

@@ -1,58 +0,0 @@
1
-package config
2
-
3
-import (
4
-	"net"
5
-	"net/url"
6
-	"strconv"
7
-)
8
-
9
-func getURLs(addr net.IP, port uint16, secret string) (urls URLs) {
10
-	values := url.Values{}
11
-	values.Set("server", addr.String())
12
-	values.Set("port", strconv.Itoa(int(port)))
13
-	values.Set("secret", secret)
14
-
15
-	urls.TG = makeTGURL(values)
16
-	urls.TMe = makeTMeURL(values)
17
-	urls.TGQRCode = makeQRCodeURL(urls.TG)
18
-	urls.TMeQRCode = makeQRCodeURL(urls.TG)
19
-
20
-	return
21
-}
22
-
23
-func makeTGURL(values url.Values) string {
24
-	tgURL := url.URL{
25
-		Scheme:   "tg",
26
-		Host:     "proxy",
27
-		RawQuery: values.Encode(),
28
-	}
29
-
30
-	return tgURL.String()
31
-}
32
-
33
-func makeTMeURL(values url.Values) string {
34
-	tMeURL := url.URL{
35
-		Scheme:   "https",
36
-		Host:     "t.me",
37
-		Path:     "proxy",
38
-		RawQuery: values.Encode(),
39
-	}
40
-
41
-	return tMeURL.String()
42
-}
43
-
44
-func makeQRCodeURL(data string) string {
45
-	qr := url.URL{
46
-		Scheme: "https",
47
-		Host:   "api.qrserver.com",
48
-		Path:   "v1/create-qr-code",
49
-	}
50
-
51
-	values := url.Values{}
52
-	values.Set("qzone", "4")
53
-	values.Set("format", "svg")
54
-	values.Set("data", data)
55
-	qr.RawQuery = values.Encode()
56
-
57
-	return qr.String()
58
-}

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

@@ -1,87 +0,0 @@
1
-package mtproto
2
-
3
-import (
4
-	"bytes"
5
-	"net"
6
-
7
-	"github.com/juju/errors"
8
-)
9
-
10
-// ConnectionType is a type of obfuscated2/mtproto connection requested
11
-// by the user.
12
-type ConnectionType uint8
13
-
14
-// ConnectionProtocol is a type of IP protocol to use.
15
-type ConnectionProtocol uint8
16
-
17
-// Hacks is a simple structure to store flags for packet transmission.
18
-type Hacks struct {
19
-	SimpleAck bool
20
-	QuickAck  bool
21
-}
22
-
23
-// ConnectionOpts presents an options, metadata on connection requested
24
-// by the user on handshake.
25
-type ConnectionOpts struct {
26
-	DC              int16
27
-	ConnectionType  ConnectionType
28
-	ConnectionProto ConnectionProtocol
29
-	// Read and Write means direction related to the client.
30
-	// ReadHacks are meant to be flushed on client read
31
-	// WriteHacks are meant to be flushed on client write.
32
-	ReadHacks  Hacks
33
-	WriteHacks Hacks
34
-	ClientAddr *net.TCPAddr
35
-}
36
-
37
-// Different connection types which user requests from Telegram.
38
-const (
39
-	ConnectionTypeUnknown ConnectionType = iota
40
-	ConnectionTypeAbridged
41
-	ConnectionTypeIntermediate
42
-	ConnectionTypeSecure
43
-)
44
-
45
-// ConnectionProtocol* define which connection protocols to use.
46
-// ConnectionProtocolAny means that any is suitable.
47
-const (
48
-	ConnectionProtocolIPv4 ConnectionProtocol = 1
49
-	ConnectionProtocolIPv6                    = ConnectionProtocolIPv4 << 1
50
-	ConnectionProtocolAny                     = ConnectionProtocolIPv4 | ConnectionProtocolIPv6
51
-)
52
-
53
-// Connection tags for mtproto handshakes.
54
-var (
55
-	ConnectionTagAbridged     = []byte{0xef, 0xef, 0xef, 0xef}
56
-	ConnectionTagIntermediate = []byte{0xee, 0xee, 0xee, 0xee}
57
-	ConnectionTagSecure       = []byte{0xdd, 0xdd, 0xdd, 0xdd}
58
-)
59
-
60
-// Tag maps connection type to the corresponding handshake tag.
61
-func (t ConnectionType) Tag() ([]byte, error) {
62
-	switch t {
63
-	case ConnectionTypeAbridged:
64
-		return ConnectionTagAbridged, nil
65
-	case ConnectionTypeIntermediate:
66
-		return ConnectionTagIntermediate, nil
67
-	case ConnectionTypeSecure:
68
-		return ConnectionTagSecure, nil
69
-	default:
70
-		return nil, errors.Errorf("Unknown connection type %d", t)
71
-	}
72
-}
73
-
74
-// ConnectionTagFromHandshake maps magic bytes to the connection type.
75
-func ConnectionTagFromHandshake(magic []byte) (ConnectionType, error) {
76
-	if bytes.Equal(magic, ConnectionTagIntermediate) {
77
-		return ConnectionTypeIntermediate, nil
78
-	}
79
-	if bytes.Equal(magic, ConnectionTagAbridged) {
80
-		return ConnectionTypeAbridged, nil
81
-	}
82
-	if bytes.Equal(magic, ConnectionTagSecure) {
83
-		return ConnectionTypeSecure, nil
84
-	}
85
-
86
-	return ConnectionTypeUnknown, errors.New("Unknown handshake protocol")
87
-}

+ 0
- 26
_mtproto/rpc/handshake_request.go Просмотреть файл

@@ -1,26 +0,0 @@
1
-package rpc
2
-
3
-import "bytes"
4
-
5
-// HandshakeRequest is the data type which is responsible for
6
-// constructing of correct handshake request.
7
-type HandshakeRequest struct {
8
-}
9
-
10
-// Bytes returns serialized handshake request.
11
-func (r *HandshakeRequest) Bytes() []byte {
12
-	buf := &bytes.Buffer{}
13
-	buf.Grow(len(TagHandshake) + len(HandshakeFlags) + len(HandshakeSenderPID) + len(HandshakePeerPID))
14
-
15
-	buf.Write(TagHandshake)       // nolint: gosec
16
-	buf.Write(HandshakeFlags)     // nolint: gosec
17
-	buf.Write(HandshakeSenderPID) // nolint: gosec
18
-	buf.Write(HandshakePeerPID)   // nolint: gosec
19
-
20
-	return buf.Bytes()
21
-}
22
-
23
-// NewHandshakeRequest creates new HandshakeRequest instance.
24
-func NewHandshakeRequest() *HandshakeRequest {
25
-	return &HandshakeRequest{}
26
-}

+ 0
- 55
_mtproto/rpc/handshake_response.go Просмотреть файл

@@ -1,55 +0,0 @@
1
-package rpc
2
-
3
-import (
4
-	"bytes"
5
-
6
-	"github.com/juju/errors"
7
-)
8
-
9
-// HandshakeResponse defines data structure which is used for storage of
10
-// handshake response.
11
-type HandshakeResponse struct {
12
-	Type      []byte
13
-	Flags     []byte
14
-	SenderPID []byte
15
-	PeerPID   []byte
16
-}
17
-
18
-// Bytes returns a serialized handshake response.
19
-func (r *HandshakeResponse) Bytes() []byte {
20
-	buf := &bytes.Buffer{}
21
-
22
-	buf.Write(r.Type)      // nolint: gosec
23
-	buf.Write(r.Flags)     // nolint: gosec
24
-	buf.Write(r.SenderPID) // nolint: gosec
25
-	buf.Write(r.PeerPID)   // nolint: gosec
26
-
27
-	return buf.Bytes()
28
-}
29
-
30
-// Valid checks that handshake response compliments request.
31
-func (r *HandshakeResponse) Valid(req *HandshakeRequest) error {
32
-	if !bytes.Equal(r.Type, TagHandshake) {
33
-		return errors.New("Unexpected handshake tag")
34
-	}
35
-	if !bytes.Equal(r.PeerPID, HandshakeSenderPID) {
36
-		return errors.New("Incorrect sender PID")
37
-	}
38
-
39
-	return nil
40
-}
41
-
42
-// NewHandshakeResponse constructs new handshake response from the given
43
-// data.
44
-func NewHandshakeResponse(data []byte) (*HandshakeResponse, error) {
45
-	if len(data) != 32 {
46
-		return nil, errors.New("Incorrect handshake response length")
47
-	}
48
-
49
-	return &HandshakeResponse{
50
-		Type:      data[:4],
51
-		Flags:     data[4:8],
52
-		SenderPID: data[8:20],
53
-		PeerPID:   data[20:],
54
-	}, nil
55
-}

+ 0
- 52
_mtproto/rpc/nonce_request.go Просмотреть файл

@@ -1,52 +0,0 @@
1
-package rpc
2
-
3
-import (
4
-	"bytes"
5
-	"crypto/rand"
6
-	"encoding/binary"
7
-	"time"
8
-
9
-	"github.com/juju/errors"
10
-)
11
-
12
-// NonceRequest is the data type which contains all the data for correct
13
-// nonce request.
14
-type NonceRequest struct {
15
-	KeySelector []byte
16
-	CryptoTS    []byte
17
-	Nonce       []byte
18
-}
19
-
20
-// Bytes returns serialized nonce request.
21
-func (r *NonceRequest) Bytes() []byte {
22
-	buf := &bytes.Buffer{}
23
-
24
-	buf.Write(TagNonce)       // nolint: gosec
25
-	buf.Write(r.KeySelector)  // nolint: gosec
26
-	buf.Write(NonceCryptoAES) // nolint: gosec
27
-	buf.Write(r.CryptoTS)     // nolint: gosec
28
-	buf.Write(r.Nonce)        // nolint: gosec
29
-
30
-	return buf.Bytes()
31
-}
32
-
33
-// NewNonceRequest builds new none request based on proxy secret.
34
-func NewNonceRequest(proxySecret []byte) (*NonceRequest, error) {
35
-	nonce := make([]byte, 16)
36
-	keySelector := make([]byte, 4)
37
-	cryptoTS := make([]byte, 4)
38
-
39
-	if _, err := rand.Read(nonce); err != nil {
40
-		return nil, errors.Annotate(err, "Cannot generate nonce")
41
-	}
42
-	copy(keySelector, proxySecret)
43
-
44
-	timestamp := time.Now().Truncate(time.Second).Unix() % 4294967296 // 256 ^ 4 - do not know how to name
45
-	binary.LittleEndian.PutUint32(cryptoTS, uint32(timestamp))
46
-
47
-	return &NonceRequest{
48
-		KeySelector: keySelector,
49
-		CryptoTS:    cryptoTS,
50
-		Nonce:       nonce,
51
-	}, nil
52
-}

+ 0
- 60
_mtproto/rpc/nonce_response.go Просмотреть файл

@@ -1,60 +0,0 @@
1
-package rpc
2
-
3
-import (
4
-	"bytes"
5
-
6
-	"github.com/juju/errors"
7
-)
8
-
9
-// NonceResponse is the data type which contains data of nonce response.
10
-type NonceResponse struct {
11
-	NonceRequest
12
-
13
-	Type   []byte
14
-	Crypto []byte
15
-}
16
-
17
-// Bytes returns serialized form of the nonce response.
18
-func (r *NonceResponse) Bytes() []byte {
19
-	buf := &bytes.Buffer{}
20
-
21
-	buf.Write(r.Type)        // nolint: gosec
22
-	buf.Write(r.KeySelector) // nolint: gosec
23
-	buf.Write(r.Crypto)      // nolint: gosec
24
-	buf.Write(r.CryptoTS)    // nolint: gosec
25
-	buf.Write(r.Nonce)       // nolint: gosec
26
-
27
-	return buf.Bytes()
28
-}
29
-
30
-// Valid checks that nonce response compliments nonce request.
31
-func (r *NonceResponse) Valid(req *NonceRequest) error {
32
-	if !bytes.Equal(r.Type, TagNonce) {
33
-		return errors.New("Unexpected RPC type")
34
-	}
35
-	if !bytes.Equal(r.Crypto, NonceCryptoAES) {
36
-		return errors.New("Unexpected crypto type")
37
-	}
38
-	if !bytes.Equal(r.KeySelector, req.KeySelector) {
39
-		return errors.New("Unexpected key selector")
40
-	}
41
-
42
-	return nil
43
-}
44
-
45
-// NewNonceResponse build new nonce response based on the given data.
46
-func NewNonceResponse(data []byte) (*NonceResponse, error) {
47
-	if len(data) != 32 {
48
-		return nil, errors.New("Unexpected message length")
49
-	}
50
-
51
-	return &NonceResponse{
52
-		NonceRequest: NonceRequest{
53
-			KeySelector: data[4:8],
54
-			CryptoTS:    data[12:16],
55
-			Nonce:       data[16:],
56
-		},
57
-		Type:   data[:4],
58
-		Crypto: data[8:12],
59
-	}, nil
60
-}

+ 0
- 59
_mtproto/rpc/proxy_flags.go Просмотреть файл

@@ -1,59 +0,0 @@
1
-package rpc
2
-
3
-import (
4
-	"encoding/binary"
5
-	"strings"
6
-)
7
-
8
-type proxyRequestFlags uint32
9
-
10
-const (
11
-	proxyRequestFlagsHasAdTag     proxyRequestFlags = 0x8
12
-	proxyRequestFlagsEncrypted    proxyRequestFlags = 0x2
13
-	proxyRequestFlagsMagic        proxyRequestFlags = 0x1000
14
-	proxyRequestFlagsExtMode2     proxyRequestFlags = 0x20000
15
-	proxyRequestFlagsIntermediate proxyRequestFlags = 0x20000000
16
-	proxyRequestFlagsAbdridged    proxyRequestFlags = 0x40000000
17
-	proxyRequestFlagsQuickAck     proxyRequestFlags = 0x80000000
18
-	proxyRequestFlagsPad          proxyRequestFlags = 0x8000000
19
-)
20
-
21
-var proxyRequestFlagsEncryptedPrefix [8]byte
22
-
23
-func (r proxyRequestFlags) Bytes() []byte {
24
-	converted := make([]byte, 4)
25
-	binary.LittleEndian.PutUint32(converted, uint32(r))
26
-
27
-	return converted
28
-}
29
-
30
-func (r proxyRequestFlags) String() string {
31
-	flags := make([]string, 0, 7)
32
-
33
-	if r&proxyRequestFlagsHasAdTag != 0 {
34
-		flags = append(flags, "HAS_AD_TAG")
35
-	}
36
-	if r&proxyRequestFlagsEncrypted != 0 {
37
-		flags = append(flags, "ENCRYPTED")
38
-	}
39
-	if r&proxyRequestFlagsMagic != 0 {
40
-		flags = append(flags, "MAGIC")
41
-	}
42
-	if r&proxyRequestFlagsExtMode2 != 0 {
43
-		flags = append(flags, "EXT_MODE_2")
44
-	}
45
-	if r&proxyRequestFlagsIntermediate != 0 {
46
-		flags = append(flags, "INTERMEDIATE")
47
-	}
48
-	if r&proxyRequestFlagsAbdridged != 0 {
49
-		flags = append(flags, "ABRIDGED")
50
-	}
51
-	if r&proxyRequestFlagsQuickAck != 0 {
52
-		flags = append(flags, "QUICK_ACK")
53
-	}
54
-	if r&proxyRequestFlagsPad != 0 {
55
-		flags = append(flags, "PAD")
56
-	}
57
-
58
-	return strings.Join(flags, " | ")
59
-}

+ 0
- 105
_mtproto/rpc/proxy_request.go Просмотреть файл

@@ -1,105 +0,0 @@
1
-package rpc
2
-
3
-import (
4
-	"bytes"
5
-	"crypto/rand"
6
-	"encoding/binary"
7
-	"fmt"
8
-	"net"
9
-
10
-	"github.com/juju/errors"
11
-
12
-	"github.com/9seconds/mtg/mtproto"
13
-)
14
-
15
-// ProxyRequest is the data type for storing data required to compose
16
-// RPC_PROXY_REQ request.
17
-type ProxyRequest struct {
18
-	Flags        proxyRequestFlags
19
-	ConnectionID []byte
20
-	OurIPPort    []byte
21
-	ClientIPPort []byte
22
-	ADTag        []byte
23
-	Options      *mtproto.ConnectionOpts
24
-}
25
-
26
-// MakeHeader makes RPC_PROXY_REQ header. We need only to append the
27
-// data for it.
28
-func (r *ProxyRequest) MakeHeader(message []byte) (*bytes.Buffer, fmt.Stringer) {
29
-	bufferLength := len(TagProxyRequest) +
30
-		4 + // len(flags)
31
-		len(r.ConnectionID) +
32
-		len(r.ClientIPPort) +
33
-		len(r.OurIPPort) +
34
-		len(ProxyRequestExtraSize) +
35
-		len(ProxyRequestProxyTag) +
36
-		1 + // len(AdTag)
37
-		len(r.ADTag)
38
-	bufferLength += bufferLength % 4
39
-
40
-	buf := &bytes.Buffer{}
41
-	buf.Grow(bufferLength + len(message))
42
-
43
-	flags := r.Flags
44
-	if r.Options.ReadHacks.QuickAck {
45
-		flags |= proxyRequestFlagsQuickAck
46
-	}
47
-
48
-	if bytes.HasPrefix(message, proxyRequestFlagsEncryptedPrefix[:]) {
49
-		flags |= proxyRequestFlagsEncrypted
50
-	}
51
-
52
-	buf.Write(TagProxyRequest)                 // nolint: gosec
53
-	buf.Write(flags.Bytes())                   // nolint: gosec
54
-	buf.Write(r.ConnectionID)                  // nolint: gosec
55
-	buf.Write(r.ClientIPPort)                  // nolint: gosec
56
-	buf.Write(r.OurIPPort)                     // nolint: gosec
57
-	buf.Write(ProxyRequestExtraSize)           // nolint: gosec
58
-	buf.Write(ProxyRequestProxyTag)            // nolint: gosec
59
-	buf.WriteByte(byte(len(r.ADTag)))          // nolint: gosec
60
-	buf.Write(r.ADTag)                         // nolint: gosec
61
-	buf.Write(make([]byte, (4-buf.Len()%4)%4)) // nolint: gosec
62
-
63
-	return buf, flags
64
-}
65
-
66
-// NewProxyRequest build new ProxyRequest data structure.
67
-func NewProxyRequest(clientAddr, ownAddr *net.TCPAddr,
68
-	opts *mtproto.ConnectionOpts, adTag []byte) (*ProxyRequest, error) {
69
-	flags := proxyRequestFlagsHasAdTag | proxyRequestFlagsMagic | proxyRequestFlagsExtMode2
70
-
71
-	switch opts.ConnectionType {
72
-	case mtproto.ConnectionTypeAbridged:
73
-		flags |= proxyRequestFlagsAbdridged
74
-	case mtproto.ConnectionTypeIntermediate:
75
-		flags |= proxyRequestFlagsIntermediate
76
-	case mtproto.ConnectionTypeSecure:
77
-		flags |= proxyRequestFlagsIntermediate | proxyRequestFlagsPad
78
-	default:
79
-		panic("Unknown connection type")
80
-	}
81
-
82
-	request := &ProxyRequest{
83
-		Flags:        flags,
84
-		ADTag:        adTag,
85
-		Options:      opts,
86
-		ConnectionID: make([]byte, 8),
87
-		ClientIPPort: make([]byte, 16+4),
88
-		OurIPPort:    make([]byte, 16+4),
89
-	}
90
-
91
-	if _, err := rand.Read(request.ConnectionID); err != nil {
92
-		return nil, errors.Annotate(err, "Cannot generate connection ID")
93
-	}
94
-
95
-	port := [4]byte{}
96
-	copy(request.ClientIPPort[:16], clientAddr.IP.To16())
97
-	binary.LittleEndian.PutUint32(port[:], uint32(clientAddr.Port))
98
-	copy(request.ClientIPPort[16:], port[:])
99
-
100
-	copy(request.OurIPPort[:16], ownAddr.IP.To16())
101
-	binary.LittleEndian.PutUint32(port[:], uint32(ownAddr.Port))
102
-	copy(request.OurIPPort[16:], port[:])
103
-
104
-	return request, nil
105
-}

+ 0
- 28
_mtproto/rpc/rpc.go Просмотреть файл

@@ -1,28 +0,0 @@
1
-package rpc
2
-
3
-// SeqNo* is the number of the sequence which have special meaning for
4
-// the Telegram.
5
-const (
6
-	SeqNoNonce     = -2
7
-	SeqNoHandshake = -1
8
-)
9
-
10
-// Different constants for RPC protocol
11
-var (
12
-	TagCloseExt     = []byte{0xa2, 0x34, 0xb6, 0x5e}
13
-	TagProxyAns     = []byte{0x0d, 0xda, 0x03, 0x44}
14
-	TagSimpleAck    = []byte{0x9b, 0x40, 0xac, 0x3b}
15
-	TagHandshake    = []byte{0xf5, 0xee, 0x82, 0x76}
16
-	TagNonce        = []byte{0xaa, 0x87, 0xcb, 0x7a}
17
-	TagProxyRequest = []byte{0xee, 0xf1, 0xce, 0x36}
18
-
19
-	NonceCryptoAES = []byte{0x01, 0x00, 0x00, 0x00}
20
-
21
-	HandshakeFlags = []byte{0x00, 0x00, 0x00, 0x00}
22
-
23
-	ProxyRequestExtraSize = []byte{0x18, 0x00, 0x00, 0x00}
24
-	ProxyRequestProxyTag  = []byte{0xae, 0x26, 0x1e, 0xdb}
25
-
26
-	HandshakeSenderPID = []byte("IPIPPRPDTIME")
27
-	HandshakePeerPID   = []byte("IPIPPRPDTIME")
28
-)

+ 0
- 121
_obfuscated2/frame.go Просмотреть файл

@@ -1,121 +0,0 @@
1
-package obfuscated2
2
-
3
-import (
4
-	"bytes"
5
-	"crypto/rand"
6
-	"encoding/binary"
7
-	"io"
8
-
9
-	"github.com/juju/errors"
10
-
11
-	"github.com/9seconds/mtg/mtproto"
12
-)
13
-
14
-// [frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd]
15
-const (
16
-	frameLenKey   = 32
17
-	frameLenIV    = 16
18
-	frameLenMagic = 4
19
-	frameLenDC    = 2
20
-
21
-	frameOffsetFirst = 8
22
-	frameOffsetKey   = frameOffsetFirst + frameLenKey
23
-	frameOffsetIV    = frameOffsetKey + frameLenIV
24
-	frameOffsetMagic = frameOffsetIV + frameLenMagic
25
-	frameOffsetDC    = frameOffsetMagic + frameLenDC
26
-
27
-	FrameLen = 64
28
-)
29
-
30
-// Frame represents handshake frame. Telegram sends 64 bytes of obfuscated2
31
-// initialization data first.
32
-// https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
33
-type Frame []byte
34
-
35
-// Key returns AES encryption key.
36
-func (f Frame) Key() []byte {
37
-	return f[frameOffsetFirst:frameOffsetKey]
38
-}
39
-
40
-// IV returns AES encryption initialization vector
41
-func (f Frame) IV() []byte {
42
-	return f[frameOffsetKey:frameOffsetIV]
43
-}
44
-
45
-// Magic returns magic bytes from last 8 bytes of frame. Telegram checks
46
-// for values there. If after decryption magic is not as expected,
47
-// connection considered as failed.
48
-func (f Frame) Magic() []byte {
49
-	return f[frameOffsetIV:frameOffsetMagic]
50
-}
51
-
52
-// DC returns number of datacenter IP client wants to use.
53
-func (f Frame) DC() (n int16) {
54
-	buf := bytes.NewReader(f[frameOffsetMagic:frameOffsetDC])
55
-	if err := binary.Read(buf, binary.LittleEndian, &n); err != nil {
56
-		n = 1
57
-	}
58
-
59
-	return
60
-}
61
-
62
-// ConnectionType identifies connection type of the handshake frame.
63
-func (f Frame) ConnectionType() (mtproto.ConnectionType, error) {
64
-	return mtproto.ConnectionTagFromHandshake(f.Magic())
65
-}
66
-
67
-// Invert inverts frame for extracting encryption keys. Pkease check that link:
68
-// https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
69
-func (f Frame) Invert() Frame {
70
-	reversed := make(Frame, FrameLen)
71
-	copy(reversed, f)
72
-
73
-	for i := 0; i < frameLenKey+frameLenIV; i++ {
74
-		reversed[frameOffsetFirst+i] = f[frameOffsetIV-1-i]
75
-	}
76
-
77
-	return reversed
78
-}
79
-
80
-// ExtractFrame extracts exact obfuscated2 handshake frame from given reader.
81
-func ExtractFrame(conn io.Reader) (Frame, error) {
82
-	frame := make(Frame, FrameLen)
83
-	buf := bytes.NewBuffer(frame)
84
-	buf.Reset()
85
-
86
-	if _, err := io.CopyN(buf, conn, FrameLen); err != nil {
87
-		return nil, errors.Annotate(err, "Cannot extract obfuscated header")
88
-	}
89
-	copy(frame, buf.Bytes())
90
-
91
-	return frame, nil
92
-}
93
-
94
-func generateFrame(connectionType mtproto.ConnectionType) Frame {
95
-	frame := make(Frame, FrameLen)
96
-
97
-	for {
98
-		if _, err := rand.Read(frame); err != nil {
99
-			continue
100
-		}
101
-		if frame[0] == 0xef {
102
-			continue
103
-		}
104
-
105
-		val := (uint32(frame[3]) << 24) | (uint32(frame[2]) << 16) | (uint32(frame[1]) << 8) | uint32(frame[0])
106
-		if val == 0x44414548 || val == 0x54534f50 || val == 0x20544547 || val == 0x4954504f || val == 0xeeeeeeee {
107
-			continue
108
-		}
109
-
110
-		val = (uint32(frame[7]) << 24) | (uint32(frame[6]) << 16) | (uint32(frame[5]) << 8) | uint32(frame[4])
111
-		if val == 0x00000000 {
112
-			continue
113
-		}
114
-
115
-		// error has to be checked before calling this function
116
-		tag, _ := connectionType.Tag() // nolint: errcheck, gosec
117
-		copy(frame.Magic(), tag)
118
-
119
-		return frame
120
-	}
121
-}

+ 0
- 106
_obfuscated2/frame_test.go Просмотреть файл

@@ -1,106 +0,0 @@
1
-package obfuscated2
2
-
3
-import (
4
-	"bytes"
5
-	"strconv"
6
-	"testing"
7
-
8
-	"github.com/stretchr/testify/assert"
9
-
10
-	"github.com/9seconds/mtg/mtproto"
11
-)
12
-
13
-func TestFrameKey(t *testing.T) {
14
-	toCompare := make([]byte, 32)
15
-	for i := 0; i < 32; i++ {
16
-		toCompare[i] = byte(1)
17
-	}
18
-
19
-	assert.Equal(t, toCompare, makeFrame().Key())
20
-}
21
-
22
-func TestFrameIV(t *testing.T) {
23
-	toCompare := make([]byte, 16)
24
-	for i := 0; i < 16; i++ {
25
-		toCompare[i] = byte(2)
26
-	}
27
-
28
-	assert.Equal(t, toCompare, makeFrame().IV())
29
-}
30
-
31
-func TestFrameMagic(t *testing.T) {
32
-	toCompare := make([]byte, 4)
33
-	for i := 0; i < 4; i++ {
34
-		toCompare[i] = 0xee
35
-	}
36
-
37
-	assert.Equal(t, toCompare, makeFrame().Magic())
38
-}
39
-
40
-func TestFrameDC(t *testing.T) {
41
-	assert.Equal(t, int16(771), makeFrame().DC())
42
-}
43
-
44
-func TestFrameValid(t *testing.T) {
45
-	frame := makeFrame()
46
-	connType, err := frame.ConnectionType()
47
-	assert.Nil(t, err)
48
-	assert.Equal(t, connType, mtproto.ConnectionTypeIntermediate)
49
-
50
-	frame[8+32+16+2] = byte(3)
51
-	_, err = frame.ConnectionType()
52
-	assert.NotNil(t, err)
53
-}
54
-
55
-func TestFrameDoubleInvert(t *testing.T) {
56
-	frame := makeFrame()
57
-	assert.True(t, bytes.Equal(frame, frame.Invert().Invert()))
58
-}
59
-
60
-func TestFrameInvert(t *testing.T) {
61
-	frame := makeFrame()
62
-	reversed := frame.Invert()
63
-
64
-	assert.Exactly(t, frame[:8], reversed[:8])
65
-	assert.Exactly(t, frame[56:], reversed[56:])
66
-
67
-	toCompare := make([]byte, 48)
68
-	for i := 0; i < 48; i++ {
69
-		toCompare[i] = frame[55-i]
70
-	}
71
-	assert.Equal(t, []byte(reversed[8:56]), toCompare)
72
-}
73
-
74
-func TestFrameGenerateValid(t *testing.T) {
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) // nolint: scopelint
82
-			conType, err := frame.ConnectionType()
83
-			assert.Nil(tt, err)
84
-			assert.Equal(tt, conType, test) // nolint: scopelint
85
-		})
86
-	}
87
-}
88
-
89
-func makeFrame() Frame {
90
-	f := make(Frame, FrameLen)
91
-
92
-	for i := 8; i < (8 + 32); i++ {
93
-		f[i] = byte(1)
94
-	}
95
-	for i := (8 + 32); i < (8 + 32 + 16); i++ {
96
-		f[i] = byte(2)
97
-	}
98
-	for i := (8 + 32 + 16); i < (8 + 32 + 16 + 4); i++ {
99
-		f[i] = 0xee
100
-	}
101
-	for i := (8 + 32 + 16 + 4); i < (8 + 32 + 16 + 4 + 2); i++ {
102
-		f[i] = byte(3)
103
-	}
104
-
105
-	return f
106
-}

+ 0
- 81
_obfuscated2/obfuscated2.go Просмотреть файл

@@ -1,81 +0,0 @@
1
-package obfuscated2
2
-
3
-import (
4
-	"crypto/aes"
5
-	"crypto/cipher"
6
-	"crypto/sha256"
7
-
8
-	"github.com/juju/errors"
9
-
10
-	"github.com/9seconds/mtg/mtproto"
11
-)
12
-
13
-// Obfuscated2 contains AES CTR encryption and decryption streams
14
-// for telegram connection.
15
-type Obfuscated2 struct {
16
-	Decryptor cipher.Stream
17
-	Encryptor cipher.Stream
18
-}
19
-
20
-// ParseObfuscated2ClientFrame parses client frame. Please check this link for
21
-// details: http://telegra.ph/telegram-blocks-wtf-05-26
22
-//
23
-// Beware, link above is in russian.
24
-func ParseObfuscated2ClientFrame(secret []byte, frame Frame) (*Obfuscated2, *mtproto.ConnectionOpts, error) {
25
-	decHasher := sha256.New()
26
-	decHasher.Write(frame.Key()) // nolint: errcheck, gosec
27
-	decHasher.Write(secret)      // nolint: errcheck, gosec
28
-	decryptor := makeStreamCipher(decHasher.Sum(nil), frame.IV())
29
-
30
-	invertedFrame := frame.Invert()
31
-	encHasher := sha256.New()
32
-	encHasher.Write(invertedFrame.Key()) // nolint: errcheck, gosec
33
-	encHasher.Write(secret)              // nolint: errcheck, gosec
34
-	encryptor := makeStreamCipher(encHasher.Sum(nil), invertedFrame.IV())
35
-
36
-	decryptedFrame := make(Frame, FrameLen)
37
-	decryptor.XORKeyStream(decryptedFrame, frame)
38
-	connType, err := decryptedFrame.ConnectionType()
39
-	if err != nil {
40
-		return nil, nil, errors.Annotate(err, "Unknown protocol")
41
-	}
42
-
43
-	obfs := &Obfuscated2{
44
-		Decryptor: decryptor,
45
-		Encryptor: encryptor,
46
-	}
47
-	connOpts := &mtproto.ConnectionOpts{
48
-		DC:             decryptedFrame.DC(),
49
-		ConnectionType: connType,
50
-	}
51
-
52
-	return obfs, connOpts, nil
53
-}
54
-
55
-// MakeTelegramObfuscated2Frame creates new handshake frame to send to
56
-// Telegram.
57
-// https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
58
-func MakeTelegramObfuscated2Frame(opts *mtproto.ConnectionOpts) (*Obfuscated2, Frame) {
59
-	frame := generateFrame(opts.ConnectionType)
60
-
61
-	encryptor := makeStreamCipher(frame.Key(), frame.IV())
62
-	decryptorFrame := frame.Invert()
63
-	decryptor := makeStreamCipher(decryptorFrame.Key(), decryptorFrame.IV())
64
-
65
-	copyFrame := make(Frame, FrameLen)
66
-	copy(copyFrame[:frameOffsetIV], frame[:frameOffsetIV])
67
-	encryptor.XORKeyStream(frame, frame)
68
-	copy(frame[:frameOffsetIV], copyFrame[:frameOffsetIV])
69
-
70
-	obfs := &Obfuscated2{
71
-		Decryptor: decryptor,
72
-		Encryptor: encryptor,
73
-	}
74
-
75
-	return obfs, frame
76
-}
77
-
78
-func makeStreamCipher(key, iv []byte) cipher.Stream {
79
-	block, _ := aes.NewCipher(key) // nolint: gosec
80
-	return cipher.NewCTR(block, iv)
81
-}

+ 0
- 97
_obfuscated2/obfuscated2_test.go Просмотреть файл

@@ -1,97 +0,0 @@
1
-package obfuscated2
2
-
3
-import (
4
-	"crypto/sha256"
5
-	"testing"
6
-
7
-	"github.com/stretchr/testify/assert"
8
-
9
-	"github.com/9seconds/mtg/mtproto"
10
-)
11
-
12
-func TestObfs2TelegramFrameDecrypt(t *testing.T) {
13
-	connOpts := &mtproto.ConnectionOpts{
14
-		DC:             1,
15
-		ConnectionType: mtproto.ConnectionTypeIntermediate,
16
-	}
17
-	_, frame := MakeTelegramObfuscated2Frame(connOpts)
18
-	decryptor := makeStreamCipher(frame.Key(), frame.IV())
19
-
20
-	decrypted := make(Frame, FrameLen)
21
-	decryptor.XORKeyStream(decrypted, frame)
22
-
23
-	_, err := decrypted.ConnectionType()
24
-	assert.Nil(t, err)
25
-}
26
-
27
-func TestObfs2TelegramDecryptEncryptDecrypt(t *testing.T) {
28
-	connOpts := &mtproto.ConnectionOpts{
29
-		DC:             1,
30
-		ConnectionType: mtproto.ConnectionTypeIntermediate,
31
-	}
32
-	obfs2, frame := MakeTelegramObfuscated2Frame(connOpts)
33
-	inverted := frame.Invert()
34
-	encryptor := makeStreamCipher(inverted.Key(), inverted.IV())
35
-
36
-	data := []byte{1, 2, 3}
37
-	encrypted := make([]byte, 3)
38
-	encryptor.XORKeyStream(encrypted, data)
39
-	decrypted := make([]byte, 3)
40
-	obfs2.Decryptor.XORKeyStream(decrypted, encrypted)
41
-
42
-	assert.Equal(t, data, decrypted)
43
-}
44
-
45
-func TestObfs2Full(t *testing.T) {
46
-	secret := []byte{1, 2, 3, 4, 5}
47
-
48
-	clientFrame := generateFrame(mtproto.ConnectionTypeIntermediate)
49
-	clientHasher := sha256.New()
50
-	clientHasher.Write(clientFrame.Key()) // nolint: errcheck, gosec
51
-	clientHasher.Write(secret)            // nolint: errcheck, gosec
52
-	clientKey := clientHasher.Sum(nil)
53
-
54
-	encryptor := makeStreamCipher(clientKey, clientFrame.IV())
55
-	encrypted := make(Frame, FrameLen)
56
-	encryptor.XORKeyStream(encrypted, clientFrame)
57
-	copy(encrypted[:56], clientFrame[:56])
58
-
59
-	invertedClientFrame := clientFrame.Invert()
60
-	clientHasher = sha256.New()
61
-	clientHasher.Write(invertedClientFrame.Key()) // nolint: errcheck, gosec
62
-	clientHasher.Write(secret)                    // nolint: errcheck, gosec
63
-	invertedClientKey := clientHasher.Sum(nil)
64
-	clientDecryptor := makeStreamCipher(invertedClientKey, invertedClientFrame.IV())
65
-
66
-	clientObfs, _, err := ParseObfuscated2ClientFrame(secret, encrypted)
67
-	assert.Nil(t, err)
68
-
69
-	connOpts := &mtproto.ConnectionOpts{
70
-		DC:             1,
71
-		ConnectionType: mtproto.ConnectionTypeIntermediate,
72
-	}
73
-	tgObfs, tgFrame := MakeTelegramObfuscated2Frame(connOpts)
74
-	tgDecryptor := makeStreamCipher(tgFrame.Key(), tgFrame.IV())
75
-	decrypted := make(Frame, FrameLen)
76
-	tgDecryptor.XORKeyStream(decrypted, tgFrame)
77
-	_, err = decrypted.ConnectionType()
78
-	assert.Nil(t, err)
79
-
80
-	tgInvertedFrame := tgFrame.Invert()
81
-	tgEncryptor := makeStreamCipher(tgInvertedFrame.Key(), tgInvertedFrame.IV())
82
-
83
-	message := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}
84
-	tgEncryptedMessage := make([]byte, len(message))
85
-	tgEncryptor.XORKeyStream(tgEncryptedMessage, message)
86
-
87
-	tgEncDecryptedMessage := make([]byte, len(tgEncryptedMessage))
88
-	tgObfs.Decryptor.XORKeyStream(tgEncDecryptedMessage, tgEncryptedMessage)
89
-	assert.Equal(t, message, tgEncDecryptedMessage)
90
-
91
-	clientEncryptedMessage := make([]byte, len(tgEncDecryptedMessage))
92
-	clientObfs.Encryptor.XORKeyStream(clientEncryptedMessage, tgEncDecryptedMessage)
93
-	finalMessage := make([]byte, len(clientEncryptedMessage))
94
-	clientDecryptor.XORKeyStream(finalMessage, clientEncryptedMessage)
95
-
96
-	assert.Equal(t, finalMessage, message)
97
-}

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

@@ -1,178 +0,0 @@
1
-package proxy
2
-
3
-import (
4
-	"context"
5
-	"io"
6
-	"net"
7
-	"sync"
8
-
9
-	"github.com/gofrs/uuid"
10
-	"github.com/juju/errors"
11
-	"go.uber.org/zap"
12
-
13
-	"github.com/9seconds/mtg/antireplay"
14
-	"github.com/9seconds/mtg/client"
15
-	"github.com/9seconds/mtg/config"
16
-	"github.com/9seconds/mtg/mtproto"
17
-	"github.com/9seconds/mtg/stats"
18
-	"github.com/9seconds/mtg/telegram"
19
-	"github.com/9seconds/mtg/wrappers"
20
-)
21
-
22
-// Proxy is a core of this program.
23
-type Proxy struct {
24
-	antiReplayCache antireplay.Cache
25
-	clientInit      client.Init
26
-	tg              telegram.Telegram
27
-	conf            *config.Config
28
-}
29
-
30
-// Serve runs TCP proxy server.
31
-func (p *Proxy) Serve() error {
32
-	lsock, err := net.Listen("tcp", p.conf.BindAddr())
33
-	if err != nil {
34
-		return errors.Annotate(err, "Cannot create listen socket")
35
-	}
36
-
37
-	for {
38
-		if conn, err := lsock.Accept(); err != nil {
39
-			zap.S().Errorw("Cannot allocate incoming connection", "error", err)
40
-		} else {
41
-			go p.accept(conn)
42
-		}
43
-	}
44
-}
45
-
46
-func (p *Proxy) accept(conn net.Conn) {
47
-	connID := uuid.Must(uuid.NewV4()).String()
48
-	log := zap.S().With("connection_id", connID).Named("main")
49
-	ctx, cancel := context.WithCancel(context.Background())
50
-
51
-	defer func() {
52
-		cancel()
53
-		conn.Close() // nolint: errcheck, gosec
54
-
55
-		if err := recover(); err != nil {
56
-			stats.NewCrash()
57
-			log.Errorw("Crash of accept handler", "error", err)
58
-		}
59
-	}()
60
-
61
-	log.Infow("Client connected", "addr", conn.RemoteAddr())
62
-
63
-	clientConn, opts, err := p.clientInit(ctx, cancel, conn, connID, p.antiReplayCache, p.conf)
64
-	if err != nil {
65
-		log.Errorw("Cannot initialize client connection", "error", err)
66
-		return
67
-	}
68
-	defer clientConn.(io.Closer).Close() // nolint: errcheck
69
-
70
-	if p.conf.SecureOnly && opts.ConnectionType != mtproto.ConnectionTypeSecure {
71
-		log.Errorw("Proxy supports only secure connections", "connection_type", opts.ConnectionType)
72
-		return
73
-	}
74
-
75
-	stats.ClientConnected(opts.ConnectionType, clientConn.RemoteAddr())
76
-	defer stats.ClientDisconnected(opts.ConnectionType, clientConn.RemoteAddr())
77
-
78
-	serverConn, err := p.getTelegramConn(ctx, cancel, opts, connID)
79
-	if err != nil {
80
-		log.Errorw("Cannot initialize server connection", "error", err)
81
-		return
82
-	}
83
-	defer serverConn.(io.Closer).Close() // nolint: errcheck
84
-
85
-	go func() {
86
-		<-ctx.Done()
87
-		serverConn.(io.Closer).Close() // nolint: gosec
88
-		clientConn.(io.Closer).Close() // nolint: gosec
89
-	}()
90
-
91
-	wait := &sync.WaitGroup{}
92
-	wait.Add(2)
93
-
94
-	if p.conf.UseMiddleProxy() {
95
-		clientPacket := clientConn.(wrappers.PacketReadWriteCloser)
96
-		serverPacket := serverConn.(wrappers.PacketReadWriteCloser)
97
-		go p.middlePipe(clientPacket, serverPacket, wait, &opts.ReadHacks)
98
-		p.middlePipe(serverPacket, clientPacket, wait, &opts.WriteHacks)
99
-	} else {
100
-		clientStream := clientConn.(wrappers.StreamReadWriteCloser)
101
-		serverStream := serverConn.(wrappers.StreamReadWriteCloser)
102
-		go p.directPipe(clientStream, serverStream, wait, p.conf.ReadBufferSize)
103
-		p.directPipe(serverStream, clientStream, wait, p.conf.WriteBufferSize)
104
-	}
105
-
106
-	wait.Wait()
107
-
108
-	log.Infow("Client disconnected", "addr", conn.RemoteAddr())
109
-}
110
-
111
-func (p *Proxy) getTelegramConn(ctx context.Context, cancel context.CancelFunc,
112
-	opts *mtproto.ConnectionOpts, connID string) (wrappers.Wrap, error) {
113
-	streamConn, err := p.tg.Dial(ctx, cancel, connID, opts)
114
-	if err != nil {
115
-		return nil, errors.Annotate(err, "Cannot dial to Telegram")
116
-	}
117
-
118
-	packetConn, err := p.tg.Init(opts, streamConn)
119
-	if err != nil {
120
-		return nil, errors.Annotate(err, "Cannot handshake telegram")
121
-	}
122
-
123
-	return packetConn, nil
124
-}
125
-
126
-func (p *Proxy) middlePipe(src wrappers.PacketReadCloser, dst io.Writer, wait *sync.WaitGroup, hacks *mtproto.Hacks) {
127
-	defer wait.Done()
128
-
129
-	for {
130
-		hacks.SimpleAck = false
131
-		hacks.QuickAck = false
132
-
133
-		packet, err := src.Read()
134
-		if err != nil {
135
-			src.Logger().Warnw("Cannot read packet", "error", err)
136
-			return
137
-		}
138
-		if _, err = dst.Write(packet); err != nil {
139
-			src.Logger().Warnw("Cannot write packet", "error", err)
140
-			return
141
-		}
142
-	}
143
-}
144
-
145
-func (p *Proxy) directPipe(src wrappers.StreamReadCloser, dst io.Writer, wait *sync.WaitGroup, bufferSize int) {
146
-	defer wait.Done()
147
-
148
-	buffer := make([]byte, bufferSize)
149
-	if _, err := io.CopyBuffer(dst, src, buffer); err != nil {
150
-		src.Logger().Warnw("Cannot pump sockets", "error", err)
151
-	}
152
-}
153
-
154
-// NewProxy returns new proxy instance.
155
-func NewProxy(conf *config.Config) (*Proxy, error) {
156
-	var clientInit client.Init
157
-	var tg telegram.Telegram
158
-
159
-	cache, err := antireplay.NewCache(conf)
160
-	if err != nil {
161
-		return nil, errors.Annotate(err, "Cannot make proxy")
162
-	}
163
-
164
-	if conf.UseMiddleProxy() {
165
-		clientInit = client.MiddleInit
166
-		tg = telegram.NewMiddleTelegram(conf)
167
-	} else {
168
-		clientInit = client.DirectInit
169
-		tg = telegram.NewDirectTelegram(conf)
170
-	}
171
-
172
-	return &Proxy{
173
-		antiReplayCache: cache,
174
-		conf:            conf,
175
-		clientInit:      clientInit,
176
-		tg:              tg,
177
-	}, nil
178
-}

+ 0
- 76
_stats/channels.go Просмотреть файл

@@ -1,76 +0,0 @@
1
-package stats
2
-
3
-import (
4
-	"net"
5
-
6
-	"github.com/9seconds/mtg/mtproto"
7
-)
8
-
9
-const (
10
-	connectionsChanLength = 10
11
-	trafficChanLength     = 10
12
-)
13
-
14
-var (
15
-	crashesChan     = make(chan struct{})
16
-	statsChan       = make(chan chan<- Stats)
17
-	connectionsChan = make(chan connectionData, connectionsChanLength)
18
-	trafficChan     = make(chan trafficData, trafficChanLength)
19
-)
20
-
21
-type connectionData struct {
22
-	connectionType mtproto.ConnectionType
23
-	connected      bool
24
-	addr           *net.TCPAddr
25
-}
26
-
27
-type trafficData struct {
28
-	traffic int
29
-	ingress bool
30
-}
31
-
32
-// NewCrash indicates new crash.
33
-func NewCrash() {
34
-	crashesChan <- struct{}{}
35
-}
36
-
37
-// ClientConnected indicates that new client was connected.
38
-func ClientConnected(connectionType mtproto.ConnectionType, addr *net.TCPAddr) {
39
-	connectionsChan <- connectionData{
40
-		connectionType: connectionType,
41
-		addr:           addr,
42
-		connected:      true,
43
-	}
44
-}
45
-
46
-// ClientDisconnected indicates that client was disconnected.
47
-func ClientDisconnected(connectionType mtproto.ConnectionType, addr *net.TCPAddr) {
48
-	connectionsChan <- connectionData{
49
-		connectionType: connectionType,
50
-		addr:           addr,
51
-		connected:      false,
52
-	}
53
-}
54
-
55
-// IngressTraffic accounts new ingress traffic.
56
-func IngressTraffic(traffic int) {
57
-	trafficChan <- trafficData{
58
-		traffic: traffic,
59
-		ingress: true,
60
-	}
61
-}
62
-
63
-// EgressTraffic accounts new ingress traffic.
64
-func EgressTraffic(traffic int) {
65
-	trafficChan <- trafficData{
66
-		traffic: traffic,
67
-		ingress: false,
68
-	}
69
-}
70
-
71
-// GetStats returns a snapshot of Stats instance.
72
-func GetStats() Stats {
73
-	rpcChan := make(chan Stats)
74
-	statsChan <- rpcChan
75
-	return <-rpcChan
76
-}

+ 0
- 28
_stats/init.go Просмотреть файл

@@ -1,28 +0,0 @@
1
-package stats
2
-
3
-import (
4
-	"github.com/juju/errors"
5
-
6
-	"github.com/9seconds/mtg/config"
7
-)
8
-
9
-// Init initializes stats subsystem.
10
-func Init(conf *config.Config) error {
11
-	if conf.StatsD.Enabled {
12
-		client, err := newStatsd(conf)
13
-		if err != nil {
14
-			return errors.Annotate(err, "Cannot initialize statsd client")
15
-		}
16
-		go client.run()
17
-	}
18
-	prometheus, err := newPrometheus(conf)
19
-	if err != nil {
20
-		return errors.Annotate(err, "Cannot initialize prometheus client")
21
-	}
22
-	go prometheus.run()
23
-
24
-	go NewStats(conf).start()
25
-	go startServer(conf, prometheus.getHTTPHandler())
26
-
27
-	return nil
28
-}

+ 0
- 91
_stats/prometheus.go Просмотреть файл

@@ -1,91 +0,0 @@
1
-package stats
2
-
3
-import (
4
-	"net/http"
5
-	"time"
6
-
7
-	"github.com/juju/errors"
8
-	"github.com/prometheus/client_golang/prometheus"
9
-	"github.com/prometheus/client_golang/prometheus/promhttp"
10
-
11
-	"github.com/9seconds/mtg/config"
12
-)
13
-
14
-const prometheusPollTime = time.Second
15
-
16
-type prometheusExporter struct {
17
-	registry prometheus.Gatherer
18
-
19
-	connections *prometheus.GaugeVec
20
-	traffic     *prometheus.GaugeVec
21
-	speed       *prometheus.GaugeVec
22
-	crashes     prometheus.Gauge
23
-}
24
-
25
-func (p *prometheusExporter) run() {
26
-	for range time.Tick(prometheusPollTime) {
27
-		instance := GetStats()
28
-
29
-		p.connections.WithLabelValues("abridged", "v4").Set(float64(instance.Connections.Abridged.IPv4))
30
-		p.connections.WithLabelValues("abridged", "v6").Set(float64(instance.Connections.Abridged.IPv6))
31
-		p.connections.WithLabelValues("intermediate", "v4").Set(float64(instance.Connections.Intermediate.IPv4))
32
-		p.connections.WithLabelValues("intermediate", "v6").Set(float64(instance.Connections.Intermediate.IPv6))
33
-		p.connections.WithLabelValues("secure", "v4").Set(float64(instance.Connections.Secure.IPv4))
34
-		p.connections.WithLabelValues("secure", "v6").Set(float64(instance.Connections.Secure.IPv6))
35
-		p.traffic.WithLabelValues("ingress").Set(float64(instance.Traffic.ingress))
36
-		p.traffic.WithLabelValues("egress").Set(float64(instance.Traffic.egress))
37
-		p.speed.WithLabelValues("ingress").Set(float64(instance.Speed.ingress))
38
-		p.speed.WithLabelValues("egress").Set(float64(instance.Speed.egress))
39
-		p.crashes.Set(float64(instance.Crashes))
40
-	}
41
-}
42
-
43
-func (p *prometheusExporter) getHTTPHandler() http.Handler {
44
-	return promhttp.HandlerFor(p.registry, promhttp.HandlerOpts{})
45
-}
46
-
47
-func newPrometheus(conf *config.Config) (*prometheusExporter, error) {
48
-	registry := prometheus.NewRegistry()
49
-
50
-	connections := prometheus.NewGaugeVec(prometheus.GaugeOpts{
51
-		Namespace: conf.Prometheus.Prefix,
52
-		Name:      "connections",
53
-		Help:      "Current number of connections to the proxy.",
54
-	}, []string{"type", "protocol"})
55
-	traffic := prometheus.NewGaugeVec(prometheus.GaugeOpts{
56
-		Namespace: conf.Prometheus.Prefix,
57
-		Name:      "traffic",
58
-		Help:      "Traffic passed through the proxy in bytes.",
59
-	}, []string{"direction"})
60
-	speed := prometheus.NewGaugeVec(prometheus.GaugeOpts{
61
-		Namespace: conf.Prometheus.Prefix,
62
-		Name:      "speed",
63
-		Help:      "Current throughput in bytes per second.",
64
-	}, []string{"direction"})
65
-	crashes := prometheus.NewGauge(prometheus.GaugeOpts{
66
-		Namespace: conf.Prometheus.Prefix,
67
-		Name:      "crashes",
68
-		Help:      "How many crashes happened.",
69
-	})
70
-
71
-	if err := registry.Register(connections); err != nil {
72
-		return nil, errors.Annotate(err, "Cannot register connections collector")
73
-	}
74
-	if err := registry.Register(traffic); err != nil {
75
-		return nil, errors.Annotate(err, "cannot register traffic collector")
76
-	}
77
-	if err := registry.Register(speed); err != nil {
78
-		return nil, errors.Annotate(err, "cannot register speed collector")
79
-	}
80
-	if err := registry.Register(crashes); err != nil {
81
-		return nil, errors.Annotate(err, "cannot register crashes collector")
82
-	}
83
-
84
-	return &prometheusExporter{
85
-		registry:    registry,
86
-		connections: connections,
87
-		traffic:     traffic,
88
-		speed:       speed,
89
-		crashes:     crashes,
90
-	}, nil
91
-}

+ 0
- 40
_stats/server.go Просмотреть файл

@@ -1,40 +0,0 @@
1
-package stats
2
-
3
-import (
4
-	"encoding/json"
5
-	"net/http"
6
-
7
-	"go.uber.org/zap"
8
-
9
-	"github.com/9seconds/mtg/config"
10
-)
11
-
12
-func startServer(conf *config.Config, prometheusHandler http.Handler) {
13
-	log := zap.S().Named("stats")
14
-
15
-	http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
16
-		w.Header().Set("Content-Type", "application/json")
17
-
18
-		first, err := json.Marshal(GetStats())
19
-		if err != nil {
20
-			log.Errorw("Cannot encode json", "error", err)
21
-			http.Error(w, "Internal server error", 500)
22
-			return
23
-		}
24
-
25
-		interim := map[string]interface{}{}
26
-		json.Unmarshal(first, &interim) // nolint: errcheck, gosec
27
-
28
-		encoder := json.NewEncoder(w)
29
-		encoder.SetEscapeHTML(false)
30
-		encoder.SetIndent("", "  ")
31
-		if err = encoder.Encode(interim); err != nil {
32
-			log.Errorw("Cannot encode json", "error", err)
33
-		}
34
-	})
35
-	http.Handle("/prometheus/", prometheusHandler)
36
-
37
-	if err := http.ListenAndServe(conf.StatAddr(), nil); err != nil {
38
-		log.Fatalw("Stats server has been stopped", "error", err)
39
-	}
40
-}

+ 0
- 175
_stats/stats.go Просмотреть файл

@@ -1,175 +0,0 @@
1
-package stats
2
-
3
-import (
4
-	"encoding/json"
5
-	"fmt"
6
-	"strconv"
7
-	"time"
8
-
9
-	humanize "github.com/dustin/go-humanize"
10
-
11
-	"github.com/9seconds/mtg/config"
12
-	"github.com/9seconds/mtg/mtproto"
13
-)
14
-
15
-type uptime time.Time
16
-
17
-func (u uptime) MarshalJSON() ([]byte, error) {
18
-	duration := time.Since(time.Time(u))
19
-	value := map[string]string{
20
-		"seconds": strconv.Itoa(int(duration.Seconds())),
21
-		"human":   humanize.Time(time.Time(u)),
22
-	}
23
-
24
-	return json.Marshal(value)
25
-}
26
-
27
-type connectionType struct {
28
-	IPv6 uint32 `json:"ipv6"`
29
-	IPv4 uint32 `json:"ipv4"`
30
-}
31
-
32
-type baseConnections struct {
33
-	All          connectionType `json:"all"`
34
-	Abridged     connectionType `json:"abridged"`
35
-	Intermediate connectionType `json:"intermediate"`
36
-	Secure       connectionType `json:"secure"`
37
-}
38
-
39
-type connections struct {
40
-	baseConnections
41
-}
42
-
43
-func (c connections) MarshalJSON() ([]byte, error) {
44
-	c.All.IPv4 = c.Abridged.IPv4 + c.Intermediate.IPv4 + c.Secure.IPv4
45
-	c.All.IPv6 = c.Abridged.IPv6 + c.Intermediate.IPv6 + c.Secure.IPv6
46
-
47
-	return json.Marshal(c.baseConnections)
48
-}
49
-
50
-type traffic struct {
51
-	ingress uint64
52
-	egress  uint64
53
-}
54
-
55
-func (t *traffic) dumpValue(value uint64) map[string]interface{} {
56
-	return map[string]interface{}{
57
-		"bytes": value,
58
-		"human": humanize.Bytes(value),
59
-	}
60
-}
61
-
62
-func (t traffic) MarshalJSON() ([]byte, error) {
63
-	value := map[string]map[string]interface{}{
64
-		"ingress": t.dumpValue(t.ingress),
65
-		"egress":  t.dumpValue(t.egress),
66
-	}
67
-
68
-	return json.Marshal(value)
69
-}
70
-
71
-type speed struct {
72
-	ingress uint64
73
-	egress  uint64
74
-}
75
-
76
-func (s *speed) dumpValue(value uint64) map[string]interface{} {
77
-	return map[string]interface{}{
78
-		"bytes/s": value,
79
-		"human":   fmt.Sprintf("%s/s", humanize.Bytes(value)),
80
-	}
81
-}
82
-
83
-func (s speed) MarshalJSON() ([]byte, error) {
84
-	value := map[string]map[string]interface{}{
85
-		"ingress": s.dumpValue(s.ingress),
86
-		"egress":  s.dumpValue(s.egress),
87
-	}
88
-
89
-	return json.Marshal(value)
90
-}
91
-
92
-// Stats represents a statistics of the proxy.
93
-type Stats struct {
94
-	URLs        config.IPURLs `json:"urls"`
95
-	Connections connections   `json:"connections"`
96
-	Traffic     traffic       `json:"traffic"`
97
-	Speed       speed         `json:"speed"`
98
-	Uptime      uptime        `json:"uptime"`
99
-	Crashes     uint32        `json:"crashes"`
100
-
101
-	previousTraffic traffic
102
-}
103
-
104
-func (s *Stats) start() {
105
-	speedChan := time.Tick(time.Second)
106
-
107
-	for {
108
-		select {
109
-		case <-speedChan:
110
-			s.handleSpeed()
111
-		case event := <-trafficChan:
112
-			s.handleTraffic(event)
113
-		case event := <-connectionsChan:
114
-			s.handleConnection(event)
115
-		case getStatsChan := <-statsChan:
116
-			s.handleGetStats(getStatsChan)
117
-		case <-crashesChan:
118
-			s.handleCrash()
119
-		}
120
-	}
121
-}
122
-
123
-func (s *Stats) handleTraffic(evt trafficData) {
124
-	if evt.ingress {
125
-		s.Traffic.ingress += uint64(evt.traffic)
126
-	} else {
127
-		s.Traffic.egress += uint64(evt.traffic)
128
-	}
129
-}
130
-
131
-func (s *Stats) handleSpeed() {
132
-	s.Speed.ingress = s.Traffic.ingress - s.previousTraffic.ingress
133
-	s.Speed.egress = s.Traffic.egress - s.previousTraffic.egress
134
-	s.previousTraffic.ingress = s.Traffic.ingress
135
-	s.previousTraffic.egress = s.Traffic.egress
136
-}
137
-
138
-func (s *Stats) handleConnection(evt connectionData) {
139
-	var inc uint32 = 1
140
-	if !evt.connected {
141
-		inc = ^uint32(0)
142
-	}
143
-
144
-	var conn *connectionType
145
-	switch evt.connectionType {
146
-	case mtproto.ConnectionTypeAbridged:
147
-		conn = &s.Connections.Abridged
148
-	case mtproto.ConnectionTypeSecure:
149
-		conn = &s.Connections.Secure
150
-	default:
151
-		conn = &s.Connections.Intermediate
152
-	}
153
-
154
-	if evt.addr.IP.To4() != nil {
155
-		conn.IPv4 += inc
156
-	} else {
157
-		conn.IPv6 += inc
158
-	}
159
-}
160
-
161
-func (s *Stats) handleGetStats(getStatsChan chan<- Stats) {
162
-	getStatsChan <- *s
163
-}
164
-
165
-func (s *Stats) handleCrash() {
166
-	s.Crashes++
167
-}
168
-
169
-// NewStats creates a new instance of Stats structure.
170
-func NewStats(conf *config.Config) *Stats {
171
-	return &Stats{
172
-		URLs:   conf.GetURLs(),
173
-		Uptime: uptime(time.Now()),
174
-	}
175
-}

+ 0
- 77
_stats/statsd.go Просмотреть файл

@@ -1,77 +0,0 @@
1
-package stats
2
-
3
-import (
4
-	"time"
5
-
6
-	"github.com/juju/errors"
7
-	statsd "gopkg.in/alexcesaro/statsd.v2"
8
-
9
-	"github.com/9seconds/mtg/config"
10
-)
11
-
12
-const (
13
-	statsdConnectionsAbridgedV4 = "connections.abridged.ipv4"
14
-	statsdConnectionsAbridgedV6 = "connections.abridged.ipv6"
15
-
16
-	statsdConnectionsIntermediateV4 = "connections.intermediate.ipv4"
17
-	statsdConnectionsIntermediateV6 = "connections.intermediate.ipv6"
18
-
19
-	statsdConnectionsSecureV4 = "connections.secure.ipv4"
20
-	statsdConnectionsSecureV6 = "connections.secure.ipv6"
21
-
22
-	statsdTrafficIngress = "traffic.ingress"
23
-	statsdTrafficEgress  = "traffic.egress"
24
-
25
-	statsdSpeedIngress = "speed.ingress"
26
-	statsdSpeedEgress  = "speed.egress"
27
-
28
-	statsdCrashes = "crashes"
29
-)
30
-
31
-const statsdPollTime = time.Second
32
-
33
-type statsdExporter struct {
34
-	client *statsd.Client
35
-}
36
-
37
-func (s *statsdExporter) run() {
38
-	for range time.Tick(statsdPollTime) {
39
-		instance := GetStats()
40
-
41
-		s.client.Gauge(statsdConnectionsAbridgedV4, instance.Connections.Abridged.IPv4)
42
-		s.client.Gauge(statsdConnectionsAbridgedV6, instance.Connections.Abridged.IPv6)
43
-		s.client.Gauge(statsdConnectionsIntermediateV4, instance.Connections.Intermediate.IPv4)
44
-		s.client.Gauge(statsdConnectionsIntermediateV6, instance.Connections.Intermediate.IPv6)
45
-		s.client.Gauge(statsdConnectionsSecureV4, instance.Connections.Secure.IPv4)
46
-		s.client.Gauge(statsdConnectionsSecureV6, instance.Connections.Secure.IPv6)
47
-		s.client.Gauge(statsdTrafficIngress, instance.Traffic.ingress)
48
-		s.client.Gauge(statsdTrafficEgress, instance.Traffic.egress)
49
-		s.client.Gauge(statsdSpeedIngress, instance.Speed.ingress)
50
-		s.client.Gauge(statsdSpeedEgress, instance.Speed.egress)
51
-		s.client.Gauge(statsdCrashes, instance.Crashes)
52
-	}
53
-}
54
-
55
-func newStatsd(conf *config.Config) (*statsdExporter, error) {
56
-	options := []statsd.Option{
57
-		statsd.Network(conf.StatsD.Addr.Network()),
58
-		statsd.Address(conf.StatsD.Addr.String()),
59
-		statsd.Prefix(conf.StatsD.Prefix),
60
-	}
61
-
62
-	if conf.StatsD.TagsFormat > 0 {
63
-		options = append(options, statsd.TagsFormat(conf.StatsD.TagsFormat))
64
-		tags := make([]string, len(conf.StatsD.Tags)*2)
65
-		for k, v := range conf.StatsD.Tags {
66
-			tags = append(tags, k, v)
67
-		}
68
-		options = append(options, statsd.Tags(tags...))
69
-	}
70
-
71
-	client, err := statsd.New(options...)
72
-	if err != nil {
73
-		return nil, errors.Annotate(err, "Cannot create statsd client")
74
-	}
75
-
76
-	return &statsdExporter{client: client}, nil
77
-}

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

@@ -1,52 +0,0 @@
1
-package telegram
2
-
3
-import (
4
-	"context"
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 telegramDialTimeout = 10 * 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
-	conn, err := t.Dialer.Dial("tcp", addr)
24
-	if err != nil {
25
-		return nil, errors.Annotate(err, "Cannot connect to Telegram")
26
-	}
27
-
28
-	tcpSocket := conn.(*net.TCPConn)
29
-	if err = tcpSocket.SetNoDelay(true); err != nil {
30
-		return nil, errors.Annotate(err, "Cannot set NO_DELAY to Telegram")
31
-	}
32
-	if err = tcpSocket.SetReadBuffer(t.conf.WriteBufferSize); err != nil {
33
-		return nil, errors.Annotate(err, "Cannot set read buffer size on telegram socket")
34
-	}
35
-	if err = tcpSocket.SetWriteBuffer(t.conf.ReadBufferSize); err != nil {
36
-		return nil, errors.Annotate(err, "Cannot set write buffer size on telegram socket")
37
-	}
38
-
39
-	return conn, nil
40
-}
41
-
42
-func (t *tgDialer) dialRWC(ctx context.Context, cancel context.CancelFunc,
43
-	addr, connID string) (wrappers.StreamReadWriteCloser, error) {
44
-	conn, err := t.dial(addr)
45
-	if err != nil {
46
-		return nil, err
47
-	}
48
-	tgConn := wrappers.NewConn(ctx, cancel, conn, connID,
49
-		wrappers.ConnPurposeTelegram, t.conf.PublicIPv4, t.conf.PublicIPv6)
50
-
51
-	return tgConn, nil
52
-}

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

@@ -1,79 +0,0 @@
1
-package telegram
2
-
3
-import (
4
-	"context"
5
-	"net"
6
-
7
-	"github.com/juju/errors"
8
-
9
-	"github.com/9seconds/mtg/config"
10
-	"github.com/9seconds/mtg/mtproto"
11
-	"github.com/9seconds/mtg/obfuscated2"
12
-	"github.com/9seconds/mtg/wrappers"
13
-)
14
-
15
-const (
16
-	directV4DefaultIdx = 1
17
-	directV6DefaultIdx = 1
18
-)
19
-
20
-var (
21
-	directV4Addresses = map[int16][]string{
22
-		0: {"149.154.175.50:443"},
23
-		1: {"149.154.167.51:443"},
24
-		2: {"149.154.175.100:443"},
25
-		3: {"149.154.167.91:443"},
26
-		4: {"149.154.171.5:443"},
27
-	}
28
-	directV6Addresses = map[int16][]string{
29
-		0: {"[2001:b28:f23d:f001::a]:443"},
30
-		1: {"[2001:67c:04e8:f002::a]:443"},
31
-		2: {"[2001:b28:f23d:f003::a]:443"},
32
-		3: {"[2001:67c:04e8:f004::a]:443"},
33
-		4: {"[2001:b28:f23f:f005::a]:443"},
34
-	}
35
-)
36
-
37
-type directTelegram struct {
38
-	baseTelegram
39
-}
40
-
41
-func (t *directTelegram) Dial(ctx context.Context, cancel context.CancelFunc,
42
-	connID string, connOpts *mtproto.ConnectionOpts) (wrappers.StreamReadWriteCloser, error) {
43
-	dc := connOpts.DC
44
-	if dc < 0 {
45
-		dc = -dc
46
-	} else if dc == 0 {
47
-		dc = 1
48
-	}
49
-
50
-	return t.baseTelegram.dial(ctx, cancel, dc-1, connID, connOpts.ConnectionProto)
51
-}
52
-
53
-func (t *directTelegram) Init(connOpts *mtproto.ConnectionOpts,
54
-	conn wrappers.StreamReadWriteCloser) (wrappers.Wrap, error) {
55
-	obfs2, frame := obfuscated2.MakeTelegramObfuscated2Frame(connOpts)
56
-
57
-	if _, err := conn.Write(frame); err != nil {
58
-		return nil, errors.Annotate(err, "Cannot write hadnshake frame")
59
-	}
60
-
61
-	return wrappers.NewStreamCipher(conn, obfs2.Encryptor, obfs2.Decryptor), nil
62
-}
63
-
64
-// NewDirectTelegram returns Telegram instance which connects directly
65
-// to Telegram bypassing middleproxies.
66
-func NewDirectTelegram(conf *config.Config) Telegram {
67
-	return &directTelegram{
68
-		baseTelegram: baseTelegram{
69
-			dialer: tgDialer{
70
-				Dialer: net.Dialer{Timeout: telegramDialTimeout},
71
-				conf:   conf,
72
-			},
73
-			v4DefaultIdx: directV4DefaultIdx,
74
-			v6DefaultIdx: directV6DefaultIdx,
75
-			v4Addresses:  directV4Addresses,
76
-			v6Addresses:  directV6Addresses,
77
-		},
78
-	}
79
-}

+ 0
- 139
_telegram/middle.go Просмотреть файл

@@ -1,139 +0,0 @@
1
-package telegram
2
-
3
-import (
4
-	"io"
5
-	"net"
6
-	"net/http"
7
-	"sync"
8
-
9
-	"github.com/juju/errors"
10
-
11
-	"github.com/9seconds/mtg/config"
12
-	"github.com/9seconds/mtg/mtproto"
13
-	"github.com/9seconds/mtg/mtproto/rpc"
14
-	"github.com/9seconds/mtg/wrappers"
15
-)
16
-
17
-type middleTelegram struct {
18
-	middleTelegramCaller
19
-
20
-	conf *config.Config
21
-}
22
-
23
-func (t *middleTelegram) Init(connOpts *mtproto.ConnectionOpts,
24
-	conn wrappers.StreamReadWriteCloser) (wrappers.Wrap, error) {
25
-	rpcNonceConn := wrappers.NewMTProtoFrame(conn, rpc.SeqNoNonce)
26
-
27
-	rpcNonceReq, err := t.sendRPCNonceRequest(rpcNonceConn)
28
-	if err != nil {
29
-		return nil, err
30
-	}
31
-	rpcNonceResp, err := t.receiveRPCNonceResponse(rpcNonceConn, rpcNonceReq)
32
-	if err != nil {
33
-		return nil, err
34
-	}
35
-
36
-	secureConn := wrappers.NewMiddleProxyCipher(conn, rpcNonceReq, rpcNonceResp, t.proxySecret)
37
-	frameConn := wrappers.NewMTProtoFrame(secureConn, rpc.SeqNoHandshake)
38
-
39
-	rpcHandshakeReq, err := t.sendRPCHandshakeRequest(frameConn)
40
-	if err != nil {
41
-		return nil, err
42
-	}
43
-	_, err = t.receiveRPCHandshakeResponse(frameConn, rpcHandshakeReq)
44
-	if err != nil {
45
-		return nil, err
46
-	}
47
-
48
-	proxyConn, err := wrappers.NewMTProtoProxy(frameConn, connOpts, t.conf.AdTag)
49
-	if err != nil {
50
-		return nil, err
51
-	}
52
-	proxyConn.Logger().Infow("Telegram connection initialized")
53
-
54
-	return proxyConn, nil
55
-}
56
-
57
-func (t *middleTelegram) sendRPCNonceRequest(conn io.Writer) (*rpc.NonceRequest, error) {
58
-	rpcNonceReq, err := rpc.NewNonceRequest(t.proxySecret)
59
-	if err != nil {
60
-		return nil, errors.Annotate(err, "Cannot create RPC nonce request")
61
-	}
62
-	if _, err = conn.Write(rpcNonceReq.Bytes()); err != nil {
63
-		return nil, errors.Annotate(err, "Cannot send RPC nonce request")
64
-	}
65
-
66
-	return rpcNonceReq, nil
67
-}
68
-
69
-func (t *middleTelegram) receiveRPCNonceResponse(conn wrappers.PacketReader,
70
-	req *rpc.NonceRequest) (*rpc.NonceResponse, error) {
71
-	packet, err := conn.Read()
72
-	if err != nil {
73
-		return nil, errors.Annotate(err, "Cannot read RPC nonce response")
74
-	}
75
-
76
-	rpcNonceResp, err := rpc.NewNonceResponse(packet)
77
-	if err != nil {
78
-		return nil, errors.Annotate(err, "Cannot initialize RPC nonce response")
79
-	}
80
-	if err = rpcNonceResp.Valid(req); err != nil {
81
-		return nil, errors.Annotate(err, "Invalid RPC nonce response")
82
-	}
83
-
84
-	return rpcNonceResp, nil
85
-}
86
-
87
-func (t *middleTelegram) sendRPCHandshakeRequest(conn io.Writer) (*rpc.HandshakeRequest, error) {
88
-	req := rpc.NewHandshakeRequest()
89
-	if _, err := conn.Write(req.Bytes()); err != nil {
90
-		return nil, errors.Annotate(err, "Cannot send RPC handshake request")
91
-	}
92
-
93
-	return req, nil
94
-}
95
-
96
-func (t *middleTelegram) receiveRPCHandshakeResponse(conn wrappers.PacketReader,
97
-	req *rpc.HandshakeRequest) (*rpc.HandshakeResponse, error) {
98
-	packet, err := conn.Read()
99
-	if err != nil {
100
-		return nil, errors.Annotate(err, "Cannot read RPC handshake response")
101
-	}
102
-
103
-	rpcHandshakeResp, err := rpc.NewHandshakeResponse(packet)
104
-	if err != nil {
105
-		return nil, errors.Annotate(err, "Cannot initialize RPC handshake response")
106
-	}
107
-	if err = rpcHandshakeResp.Valid(req); err != nil {
108
-		return nil, errors.Annotate(err, "Invalid RPC handshake response")
109
-	}
110
-
111
-	return rpcHandshakeResp, nil
112
-}
113
-
114
-// NewMiddleTelegram creates new instance of Telegram which works with
115
-// middle proxies.
116
-func NewMiddleTelegram(conf *config.Config) Telegram {
117
-	tg := &middleTelegram{
118
-		middleTelegramCaller: middleTelegramCaller{
119
-			baseTelegram: baseTelegram{
120
-				dialer: tgDialer{
121
-					Dialer: net.Dialer{Timeout: telegramDialTimeout},
122
-					conf:   conf,
123
-				},
124
-			},
125
-			httpClient: &http.Client{
126
-				Timeout: middleTelegramHTTPClientTimeout,
127
-			},
128
-			dialerMutex: &sync.RWMutex{},
129
-		},
130
-		conf: conf,
131
-	}
132
-
133
-	if err := tg.update(); err != nil {
134
-		panic(err)
135
-	}
136
-	go tg.autoUpdate()
137
-
138
-	return tg
139
-}

+ 0
- 191
_telegram/middle_caller.go Просмотреть файл

@@ -1,191 +0,0 @@
1
-package telegram
2
-
3
-import (
4
-	"bufio"
5
-	"context"
6
-	"io/ioutil"
7
-	"net"
8
-	"net/http"
9
-	"regexp"
10
-	"strconv"
11
-	"strings"
12
-	"sync"
13
-	"time"
14
-
15
-	"github.com/juju/errors"
16
-	"go.uber.org/zap"
17
-
18
-	"github.com/9seconds/mtg/mtproto"
19
-	"github.com/9seconds/mtg/wrappers"
20
-)
21
-
22
-const (
23
-	middleTelegramAutoUpdateInterval = 6 * time.Hour
24
-	middleTelegramHTTPClientTimeout  = 30 * time.Second
25
-
26
-	tgAddrProxySecret = "https://core.telegram.org/getProxySecret"   // nolint: gas
27
-	tgAddrProxyV4     = "https://core.telegram.org/getProxyConfig"   // nolint: gas
28
-	tgAddrProxyV6     = "https://core.telegram.org/getProxyConfigV6" // nolint: gas
29
-	tgUserAgent       = "mtg"
30
-)
31
-
32
-var middleTelegramProxyConfigSplitter = regexp.MustCompile(`\s+`)
33
-
34
-type middleTelegramCaller struct {
35
-	baseTelegram
36
-
37
-	proxySecret []byte
38
-	dialerMutex *sync.RWMutex
39
-	httpClient  *http.Client
40
-}
41
-
42
-func (t *middleTelegramCaller) Dial(ctx context.Context, cancel context.CancelFunc, connID string,
43
-	connOpts *mtproto.ConnectionOpts) (wrappers.StreamReadWriteCloser, error) {
44
-	dc := connOpts.DC
45
-	if dc == 0 {
46
-		dc = 1
47
-	}
48
-	t.dialerMutex.RLock()
49
-	defer t.dialerMutex.RUnlock()
50
-
51
-	return t.baseTelegram.dial(ctx, cancel, dc, connID, connOpts.ConnectionProto)
52
-}
53
-
54
-func (t *middleTelegramCaller) autoUpdate() {
55
-	for range time.Tick(middleTelegramAutoUpdateInterval) {
56
-		if err := t.update(); err != nil {
57
-			zap.S().Warnw("Cannot update from Telegram", "error", err)
58
-		}
59
-	}
60
-}
61
-
62
-func (t *middleTelegramCaller) update() error {
63
-	secret, err := t.getTelegramProxySecret()
64
-	if err != nil {
65
-		return errors.Annotate(err, "Cannot get proxy secret")
66
-	}
67
-
68
-	v4Addresses, v4DefaultIdx, err := t.getTelegramAddresses(tgAddrProxyV4)
69
-	if err != nil {
70
-		return errors.Annotate(err, "Cannot get ipv4 addresses")
71
-	}
72
-
73
-	v6Addresses, v6DefaultIdx, err := t.getTelegramAddresses(tgAddrProxyV6)
74
-	if err != nil {
75
-		return errors.Annotate(err, "Cannot get ipv6 addresses")
76
-	}
77
-
78
-	t.dialerMutex.Lock()
79
-	t.proxySecret = secret
80
-	t.v4DefaultIdx = v4DefaultIdx
81
-	t.v6DefaultIdx = v6DefaultIdx
82
-	t.v4Addresses = v4Addresses
83
-	t.v6Addresses = v6Addresses
84
-	t.dialerMutex.Unlock()
85
-
86
-	zap.S().Infow("Telegram middle proxy data has been updated")
87
-
88
-	return nil
89
-}
90
-
91
-func (t *middleTelegramCaller) getTelegramProxySecret() ([]byte, error) {
92
-	resp, err := t.call(tgAddrProxySecret)
93
-	if err != nil {
94
-		return nil, errors.Annotate(err, "Cannot access telegram server")
95
-	}
96
-	defer resp.Body.Close() // nolint: errcheck
97
-
98
-	secret, err := ioutil.ReadAll(resp.Body)
99
-	if err != nil {
100
-		return nil, errors.Annotate(err, "Cannot read response")
101
-	}
102
-
103
-	return secret, nil
104
-}
105
-
106
-func (t *middleTelegramCaller) getTelegramAddresses(url string) (map[int16][]string, int16, error) { // nolint: gocyclo
107
-	resp, err := t.call(url)
108
-	if err != nil {
109
-		return nil, 0, errors.Annotate(err, "Cannot access telegram server")
110
-	}
111
-	defer resp.Body.Close() // nolint: errcheck
112
-
113
-	scanner := bufio.NewScanner(resp.Body)
114
-	data := map[int16][]string{}
115
-
116
-	var defaultIdx int16 = 1
117
-	for scanner.Scan() {
118
-		text := strings.TrimSpace(scanner.Text())
119
-		switch {
120
-		case strings.HasPrefix(text, "#"):
121
-			continue
122
-		case strings.HasPrefix(text, "proxy_for"):
123
-			addr, idx, err2 := t.parseProxyFor(text)
124
-			if err2 != nil {
125
-				return nil, 0, errors.Annotate(err2, "Cannot parse 'proxy_for' section")
126
-			}
127
-			if addresses, ok := data[idx]; ok {
128
-				data[idx] = append(addresses, addr)
129
-			} else {
130
-				data[idx] = []string{addr}
131
-			}
132
-		case strings.HasPrefix(text, "default"):
133
-			idx, err2 := t.parseDefault(text)
134
-			if err2 != nil {
135
-				return nil, 0, errors.Annotate(err2, "Cannot parse 'default' section")
136
-			}
137
-			defaultIdx = idx
138
-		default:
139
-			return nil, 0, errors.Errorf("Unknown config string '%s'", text)
140
-		}
141
-	}
142
-
143
-	err = scanner.Err()
144
-	if err != nil {
145
-		return nil, 0, errors.Annotate(err, "Cannot read response from the telegram")
146
-	}
147
-
148
-	return data, defaultIdx, nil
149
-}
150
-
151
-func (t *middleTelegramCaller) parseProxyFor(text string) (string, int16, error) {
152
-	chunks := middleTelegramProxyConfigSplitter.Split(text, 3)
153
-	if len(chunks) != 3 || chunks[0] != "proxy_for" {
154
-		return "", 0, errors.Errorf("Incorrect config '%s'", text)
155
-	}
156
-
157
-	dcIdx, err := strconv.ParseInt(chunks[1], 10, 16)
158
-	if err != nil {
159
-		return "", 0, errors.Annotatef(err, "Incorrect config '%s'", text)
160
-	}
161
-
162
-	addr := strings.TrimRight(chunks[2], ";")
163
-	if _, _, err = net.SplitHostPort(addr); err != nil {
164
-		return "", 0, errors.Annotatef(err, "Incorrect config '%s'", text)
165
-	}
166
-
167
-	return addr, int16(dcIdx), nil
168
-}
169
-
170
-func (t *middleTelegramCaller) parseDefault(text string) (int16, error) {
171
-	chunks := middleTelegramProxyConfigSplitter.Split(text, 2)
172
-	if len(chunks) != 2 || chunks[0] != "default" {
173
-		return 0, errors.Errorf("Incorrect config '%s'", text)
174
-	}
175
-
176
-	dcIdxString := strings.TrimRight(chunks[1], ";")
177
-	dcIdx, err := strconv.ParseInt(dcIdxString, 10, 16)
178
-	if err != nil {
179
-		return 0, errors.Annotatef(err, "Incorrect config '%s'", text)
180
-	}
181
-
182
-	return int16(dcIdx), nil
183
-}
184
-
185
-func (t *middleTelegramCaller) call(url string) (*http.Response, error) {
186
-	req, _ := http.NewRequest("GET", url, nil) // nolint: gosec
187
-	req.Header.Set("Accept", "text/plain")
188
-	req.Header.Set("User-Agent", tgUserAgent)
189
-
190
-	return t.httpClient.Do(req)
191
-}

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

@@ -1,68 +0,0 @@
1
-package telegram
2
-
3
-import (
4
-	"context"
5
-	"math/rand"
6
-
7
-	"github.com/juju/errors"
8
-
9
-	"github.com/9seconds/mtg/mtproto"
10
-	"github.com/9seconds/mtg/wrappers"
11
-)
12
-
13
-// Telegram is an interface for different Telegram work modes.
14
-type Telegram interface {
15
-	Dial(context.Context, context.CancelFunc, string, *mtproto.ConnectionOpts) (wrappers.StreamReadWriteCloser, error)
16
-	Init(*mtproto.ConnectionOpts, wrappers.StreamReadWriteCloser) (wrappers.Wrap, error)
17
-}
18
-
19
-type baseTelegram struct {
20
-	dialer tgDialer
21
-
22
-	v4DefaultIdx int16
23
-	v6DefaultIdx int16
24
-	v4Addresses  map[int16][]string
25
-	v6Addresses  map[int16][]string
26
-}
27
-
28
-func (b *baseTelegram) dial(ctx context.Context, cancel context.CancelFunc, dcIdx int16, connID string,
29
-	proto mtproto.ConnectionProtocol) (wrappers.StreamReadWriteCloser, error) {
30
-	addrs := make([]string, 2)
31
-
32
-	if proto&mtproto.ConnectionProtocolIPv6 != 0 {
33
-		if addr := b.chooseAddress(b.v6Addresses, dcIdx, b.v6DefaultIdx); addr != "" {
34
-			addrs = append(addrs, addr)
35
-		}
36
-	}
37
-	if proto&mtproto.ConnectionProtocolIPv4 != 0 {
38
-		if addr := b.chooseAddress(b.v4Addresses, dcIdx, b.v4DefaultIdx); addr != "" {
39
-			addrs = append(addrs, addr)
40
-		}
41
-	}
42
-
43
-	for _, addr := range addrs {
44
-		if conn, err := b.dialer.dialRWC(ctx, cancel, addr, connID); err == nil {
45
-			return conn, err
46
-		}
47
-	}
48
-
49
-	return nil, errors.New("Cannot connect to Telegram")
50
-}
51
-
52
-func (b *baseTelegram) chooseAddress(addresses map[int16][]string, idx, defaultIdx int16) string {
53
-	if addr, ok := addresses[idx]; ok {
54
-		return b.chooseRandomAddress(addr)
55
-	} else if addr, ok := addresses[defaultIdx]; ok {
56
-		return b.chooseRandomAddress(addr)
57
-	}
58
-
59
-	return ""
60
-}
61
-
62
-func (b *baseTelegram) chooseRandomAddress(addresses []string) string {
63
-	if len(addresses) > 0 {
64
-		return addresses[rand.Intn(len(addresses))]
65
-	}
66
-
67
-	return ""
68
-}

+ 0
- 21
_utils/read_current_data.go Просмотреть файл

@@ -1,21 +0,0 @@
1
-package utils
2
-
3
-import "io"
4
-
5
-const readCurrentDataBufferSize = 1024 + 1 // + 1 because telegram operates with blocks mod 4
6
-
7
-// ReadCurrentData reads all data from io.Reader which is ready to be read.
8
-func ReadCurrentData(src io.Reader) (rv []byte, err error) {
9
-	buf := make([]byte, readCurrentDataBufferSize)
10
-	n := readCurrentDataBufferSize
11
-
12
-	for n == len(buf) {
13
-		n, err = src.Read(buf)
14
-		if err != nil {
15
-			return nil, err
16
-		}
17
-		rv = append(rv, buf[:n]...)
18
-	}
19
-
20
-	return rv, nil
21
-}

+ 0
- 15
_utils/reverse_bytes.go Просмотреть файл

@@ -1,15 +0,0 @@
1
-package utils
2
-
3
-// ReverseBytes is a common slice reverser.
4
-func ReverseBytes(data []byte) []byte {
5
-	dataLen := len(data)
6
-	rv := make([]byte, dataLen)
7
-
8
-	rv[dataLen/2] = data[dataLen/2]
9
-	for i := dataLen/2 - 1; i >= 0; i-- {
10
-		opp := dataLen - i - 1
11
-		rv[i], rv[opp] = data[opp], data[i]
12
-	}
13
-
14
-	return rv
15
-}

+ 0
- 15
_utils/uint24.go Просмотреть файл

@@ -1,15 +0,0 @@
1
-package utils
2
-
3
-// Uint24 is a replacement for the absent Go uint24 data type.
4
-// This data type is little endian.
5
-type Uint24 [3]byte
6
-
7
-// ToUint24 converts number to Uint24.
8
-func ToUint24(number uint32) Uint24 {
9
-	return Uint24{byte(number), byte(number >> 8), byte(number >> 16)}
10
-}
11
-
12
-// FromUint24 converts Uint24 to number.
13
-func FromUint24(number Uint24) uint32 {
14
-	return uint32(number[0]) + (uint32(number[1]) << 8) + (uint32(number[2]) << 16)
15
-}

+ 0
- 99
_wrappers/blockcipher.go Просмотреть файл

@@ -1,99 +0,0 @@
1
-package wrappers
2
-
3
-import (
4
-	"bytes"
5
-	"crypto/aes"
6
-	"crypto/cipher"
7
-	"net"
8
-
9
-	"go.uber.org/zap"
10
-
11
-	"github.com/9seconds/mtg/utils"
12
-	"github.com/juju/errors"
13
-)
14
-
15
-// BlockCipher is a stream writer which encrypts/decrypts blocks of data
16
-// with AES CBC. This also is buffered reader. It means, that block
17
-// reading is transparent for it, you can assume you are working with
18
-// good old io.Reader.
19
-type BlockCipher struct {
20
-	buf *bytes.Buffer
21
-
22
-	logger    *zap.SugaredLogger
23
-	conn      StreamReadWriteCloser
24
-	encryptor cipher.BlockMode
25
-	decryptor cipher.BlockMode
26
-}
27
-
28
-func (b *BlockCipher) Read(p []byte) (int, error) {
29
-	if b.buf.Len() > 0 {
30
-		return b.flush(p)
31
-	}
32
-
33
-	buf := []byte{}
34
-	for len(buf) == 0 || len(buf)%aes.BlockSize != 0 {
35
-		rv, err := utils.ReadCurrentData(b.conn)
36
-		if err != nil {
37
-			return 0, errors.Annotate(err, "Cannot read from socket")
38
-		}
39
-		buf = append(buf, rv...)
40
-	}
41
-
42
-	b.decryptor.CryptBlocks(buf, buf)
43
-	b.buf.Write(buf) // nolint: gosec
44
-
45
-	return b.flush(p)
46
-}
47
-
48
-func (b *BlockCipher) flush(p []byte) (int, error) {
49
-	if b.buf.Len() <= len(p) {
50
-		sizeToReturn := b.buf.Len()
51
-		copy(p, b.buf.Bytes())
52
-		b.buf.Reset()
53
-		return sizeToReturn, nil
54
-	}
55
-
56
-	return b.buf.Read(p)
57
-}
58
-
59
-func (b *BlockCipher) Write(p []byte) (int, error) {
60
-	if len(p)%aes.BlockSize > 0 {
61
-		return 0, errors.Errorf("Incorrect block size %d", len(p))
62
-	}
63
-
64
-	encrypted := make([]byte, len(p))
65
-	b.encryptor.CryptBlocks(encrypted, p)
66
-
67
-	return b.conn.Write(encrypted)
68
-}
69
-
70
-// Logger returns an instance of the logger for this wrapper.
71
-func (b *BlockCipher) Logger() *zap.SugaredLogger {
72
-	return b.logger
73
-}
74
-
75
-// LocalAddr returns local address of the underlying net.Conn.
76
-func (b *BlockCipher) LocalAddr() *net.TCPAddr {
77
-	return b.conn.LocalAddr()
78
-}
79
-
80
-// RemoteAddr returns remote address of the underlying net.Conn.
81
-func (b *BlockCipher) RemoteAddr() *net.TCPAddr {
82
-	return b.conn.RemoteAddr()
83
-}
84
-
85
-// Close closes underlying net.Conn.
86
-func (b *BlockCipher) Close() error {
87
-	return b.conn.Close()
88
-}
89
-
90
-// NewBlockCipher creates new instance of BlockCipher based on given data.
91
-func NewBlockCipher(conn StreamReadWriteCloser, encryptor, decryptor cipher.BlockMode) StreamReadWriteCloser {
92
-	return &BlockCipher{
93
-		buf:       &bytes.Buffer{},
94
-		conn:      conn,
95
-		logger:    conn.Logger().Named("block-cipher"),
96
-		encryptor: encryptor,
97
-		decryptor: decryptor,
98
-	}
99
-}

+ 0
- 154
_wrappers/conn.go Просмотреть файл

@@ -1,154 +0,0 @@
1
-package wrappers
2
-
3
-import (
4
-	"context"
5
-	"net"
6
-	"time"
7
-
8
-	"go.uber.org/zap"
9
-
10
-	"github.com/9seconds/mtg/stats"
11
-	"github.com/juju/errors"
12
-)
13
-
14
-// ConnPurpose is intended to be identifier of connection purpose. We
15
-// sometimes want to treat client/telegram connection differently (for
16
-// logging for example).
17
-type ConnPurpose uint8
18
-
19
-func (c ConnPurpose) String() string {
20
-	switch c {
21
-	case ConnPurposeClient:
22
-		return "client"
23
-	case ConnPurposeTelegram:
24
-		return "telegram"
25
-	}
26
-
27
-	return ""
28
-}
29
-
30
-// ConnPurpose* define different connection types.
31
-const (
32
-	ConnPurposeClient = iota
33
-	ConnPurposeTelegram
34
-)
35
-
36
-const (
37
-	connTimeoutRead  = 2 * time.Minute
38
-	connTimeoutWrite = 2 * time.Minute
39
-)
40
-
41
-// Conn is a basic wrapper for net.Conn providing the most low-level
42
-// logic and management as possible.
43
-type Conn struct {
44
-	conn   net.Conn
45
-	ctx    context.Context
46
-	cancel context.CancelFunc
47
-	connID string
48
-	logger *zap.SugaredLogger
49
-
50
-	publicIPv4 net.IP
51
-	publicIPv6 net.IP
52
-}
53
-
54
-func (c *Conn) Write(p []byte) (int, error) {
55
-	select {
56
-	case <-c.ctx.Done():
57
-		c.Close() // nolint: gosec
58
-		return 0, errors.Annotate(c.ctx.Err(), "Cannot write because context was closed")
59
-	default:
60
-		if err := c.conn.SetWriteDeadline(time.Now().Add(connTimeoutWrite)); err != nil {
61
-			c.Close() // nolint: gosec
62
-			return 0, errors.Annotate(err, "Cannot set write deadline to the socket")
63
-		}
64
-
65
-		n, err := c.conn.Write(p)
66
-		c.logger.Debugw("Write to stream", "bytes", n, "error", err)
67
-		stats.EgressTraffic(n)
68
-		if err != nil {
69
-			c.Close() // nolint: gosec
70
-		}
71
-
72
-		return n, err
73
-	}
74
-}
75
-
76
-func (c *Conn) Read(p []byte) (int, error) {
77
-	select {
78
-	case <-c.ctx.Done():
79
-		c.Close() // nolint: gosec
80
-		return 0, errors.Annotate(c.ctx.Err(), "Cannot read because context was closed")
81
-	default:
82
-		if err := c.conn.SetReadDeadline(time.Now().Add(connTimeoutRead)); err != nil {
83
-			c.Close() // nolint: gosec
84
-			return 0, errors.Annotate(err, "Cannot set read deadline to the socket")
85
-		}
86
-
87
-		n, err := c.conn.Read(p)
88
-		c.logger.Debugw("Read from stream", "bytes", n, "error", err)
89
-		stats.IngressTraffic(n)
90
-		if err != nil {
91
-			c.Close() // nolint: gosec
92
-		}
93
-
94
-		return n, err
95
-	}
96
-}
97
-
98
-// Close closes underlying net.Conn instance.
99
-func (c *Conn) Close() error {
100
-	c.logger.Debugw("Close connection")
101
-	c.cancel()
102
-
103
-	return c.conn.Close()
104
-}
105
-
106
-// Logger returns an instance of the logger for this wrapper.
107
-func (c *Conn) Logger() *zap.SugaredLogger {
108
-	return c.logger
109
-}
110
-
111
-// LocalAddr returns local address of the underlying net.Conn.
112
-func (c *Conn) LocalAddr() *net.TCPAddr {
113
-	addr := c.conn.LocalAddr().(*net.TCPAddr)
114
-	newAddr := *addr
115
-
116
-	if c.RemoteAddr().IP.To4() != nil {
117
-		if c.publicIPv4 != nil {
118
-			newAddr.IP = c.publicIPv4
119
-		}
120
-	} else if c.publicIPv6 != nil {
121
-		newAddr.IP = c.publicIPv6
122
-	}
123
-
124
-	return &newAddr
125
-}
126
-
127
-// RemoteAddr returns remote address of the underlying net.Conn.
128
-func (c *Conn) RemoteAddr() *net.TCPAddr {
129
-	return c.conn.RemoteAddr().(*net.TCPAddr)
130
-}
131
-
132
-// NewConn initializes Conn wrapper for net.Conn.
133
-func NewConn(ctx context.Context, cancel context.CancelFunc, conn net.Conn,
134
-	connID string, purpose ConnPurpose, publicIPv4, publicIPv6 net.IP) StreamReadWriteCloser {
135
-	logger := zap.S().With(
136
-		"connection_id", connID,
137
-		"local_address", conn.LocalAddr(),
138
-		"remote_address", conn.RemoteAddr(),
139
-		"purpose", purpose,
140
-	).Named("conn")
141
-
142
-	wrapper := Conn{
143
-		conn:       conn,
144
-		ctx:        ctx,
145
-		cancel:     cancel,
146
-		connID:     connID,
147
-		logger:     logger,
148
-		publicIPv4: publicIPv4,
149
-		publicIPv6: publicIPv6,
150
-	}
151
-	wrapper.logger = logger.With("faked_local_addr", wrapper.LocalAddr())
152
-
153
-	return &wrapper
154
-}

+ 0
- 159
_wrappers/mtproto_abridged.go Просмотреть файл

@@ -1,159 +0,0 @@
1
-package wrappers
2
-
3
-import (
4
-	"bytes"
5
-	"io"
6
-	"net"
7
-
8
-	"github.com/juju/errors"
9
-	"go.uber.org/zap"
10
-
11
-	"github.com/9seconds/mtg/mtproto"
12
-	"github.com/9seconds/mtg/utils"
13
-)
14
-
15
-const (
16
-	mtprotoAbridgedSmallPacketLength = 0x7f
17
-	mtprotoAbridgedQuickAckLength    = 0x80
18
-	mtprotoAbridgedLargePacketLength = 16777216 // 256 ^ 3
19
-)
20
-
21
-// MTProtoAbridged presents abridged connection between client and
22
-// middle proxy.
23
-type MTProtoAbridged struct {
24
-	conn   StreamReadWriteCloser
25
-	opts   *mtproto.ConnectionOpts
26
-	logger *zap.SugaredLogger
27
-
28
-	readCounter  uint32
29
-	writeCounter uint32
30
-}
31
-
32
-func (m *MTProtoAbridged) Read() ([]byte, error) {
33
-	defer func() {
34
-		m.readCounter++
35
-	}()
36
-
37
-	m.logger.Debugw("Read packet",
38
-		"simple_ack", m.opts.ReadHacks.SimpleAck,
39
-		"quick_ack", m.opts.ReadHacks.QuickAck,
40
-		"counter", m.readCounter,
41
-	)
42
-
43
-	buf := &bytes.Buffer{}
44
-	buf.Grow(3)
45
-
46
-	if _, err := io.CopyN(buf, m.conn, 1); err != nil {
47
-		return nil, errors.Annotate(err, "Cannot read message length")
48
-	}
49
-	msgLength := uint32(buf.Bytes()[0])
50
-	buf.Reset()
51
-
52
-	m.logger.Debugw("Packet first byte",
53
-		"byte", msgLength,
54
-		"counter", m.readCounter,
55
-		"simple_ack", m.opts.ReadHacks.SimpleAck,
56
-		"quick_ack", m.opts.ReadHacks.QuickAck,
57
-	)
58
-
59
-	if msgLength >= mtprotoAbridgedQuickAckLength {
60
-		m.opts.ReadHacks.QuickAck = true
61
-		msgLength -= mtprotoAbridgedQuickAckLength
62
-	}
63
-
64
-	if msgLength == mtprotoAbridgedSmallPacketLength {
65
-		if _, err := io.CopyN(buf, m.conn, 3); err != nil {
66
-			return nil, errors.Annotate(err, "Cannot read the correct message length")
67
-		}
68
-		number := utils.Uint24{}
69
-		copy(number[:], buf.Bytes())
70
-		msgLength = utils.FromUint24(number)
71
-	}
72
-	msgLength *= 4
73
-
74
-	m.logger.Debugw("Packet length",
75
-		"length", msgLength,
76
-		"simple_ack", m.opts.ReadHacks.SimpleAck,
77
-		"quick_ack", m.opts.ReadHacks.QuickAck,
78
-		"counter", m.readCounter,
79
-	)
80
-
81
-	buf.Reset()
82
-	buf.Grow(int(msgLength))
83
-	if _, err := io.CopyN(buf, m.conn, int64(msgLength)); err != nil {
84
-		return nil, errors.Annotate(err, "Cannot read message")
85
-	}
86
-
87
-	return buf.Bytes(), nil
88
-}
89
-
90
-func (m *MTProtoAbridged) Write(p []byte) (int, error) {
91
-	defer func() {
92
-		m.writeCounter++
93
-	}()
94
-
95
-	m.logger.Debugw("Write packet",
96
-		"length", len(p),
97
-		"simple_ack", m.opts.WriteHacks.SimpleAck,
98
-		"quick_ack", m.opts.WriteHacks.QuickAck,
99
-		"counter", m.writeCounter,
100
-	)
101
-
102
-	if len(p)%4 != 0 {
103
-		return 0, errors.Errorf("Incorrect packet length %d", len(p))
104
-	}
105
-
106
-	if m.opts.WriteHacks.SimpleAck {
107
-		return m.conn.Write(utils.ReverseBytes(p))
108
-	}
109
-
110
-	packetLength := len(p) / 4
111
-	switch {
112
-	case packetLength < mtprotoAbridgedSmallPacketLength:
113
-		newData := append([]byte{byte(packetLength)}, p...)
114
-		return m.conn.Write(newData)
115
-
116
-	case packetLength < mtprotoAbridgedLargePacketLength:
117
-		length24 := utils.ToUint24(uint32(packetLength))
118
-
119
-		buf := &bytes.Buffer{}
120
-		buf.Grow(1 + 3 + len(p))
121
-
122
-		buf.WriteByte(byte(mtprotoAbridgedSmallPacketLength)) // nolint: gosec
123
-		buf.Write(length24[:])                                // nolint: gosec
124
-		buf.Write(p)                                          // nolint: gosec
125
-
126
-		return m.conn.Write(buf.Bytes())
127
-	}
128
-
129
-	return 0, errors.Errorf("Packet is too big %d", len(p))
130
-}
131
-
132
-// Logger returns an instance of the logger for this wrapper.
133
-func (m *MTProtoAbridged) Logger() *zap.SugaredLogger {
134
-	return m.logger
135
-}
136
-
137
-// LocalAddr returns local address of the underlying net.Conn.
138
-func (m *MTProtoAbridged) LocalAddr() *net.TCPAddr {
139
-	return m.conn.LocalAddr()
140
-}
141
-
142
-// RemoteAddr returns remote address of the underlying net.Conn.
143
-func (m *MTProtoAbridged) RemoteAddr() *net.TCPAddr {
144
-	return m.conn.RemoteAddr()
145
-}
146
-
147
-// Close closes underlying net.Conn instance.
148
-func (m *MTProtoAbridged) Close() error {
149
-	return m.conn.Close()
150
-}
151
-
152
-// NewMTProtoAbridged creates new wrapper for abridged client connection.
153
-func NewMTProtoAbridged(conn StreamReadWriteCloser, opts *mtproto.ConnectionOpts) PacketReadWriteCloser {
154
-	return &MTProtoAbridged{
155
-		conn:   conn,
156
-		opts:   opts,
157
-		logger: conn.Logger().Named("mtproto-abridged"),
158
-	}
159
-}

+ 0
- 98
_wrappers/mtproto_cipher.go Просмотреть файл

@@ -1,98 +0,0 @@
1
-package wrappers
2
-
3
-import (
4
-	"bytes"
5
-	"crypto/aes"
6
-	"crypto/cipher"
7
-	"crypto/md5"  // nolint: gas
8
-	"crypto/sha1" // nolint: gosec
9
-	"encoding/binary"
10
-	"net"
11
-
12
-	"github.com/9seconds/mtg/mtproto/rpc"
13
-	"github.com/9seconds/mtg/utils"
14
-)
15
-
16
-type cipherPurpose uint8
17
-
18
-const (
19
-	cipherPurposeClient cipherPurpose = iota
20
-	cipherPurposeServer
21
-)
22
-
23
-var emptyIP = [4]byte{0x00, 0x00, 0x00, 0x00}
24
-
25
-// NewMiddleProxyCipher creates new block cipher to proxy<->telegram
26
-// connection.
27
-func NewMiddleProxyCipher(conn StreamReadWriteCloser,
28
-	req *rpc.NonceRequest, resp *rpc.NonceResponse, secret []byte) StreamReadWriteCloser {
29
-	localAddr := conn.LocalAddr()
30
-	remoteAddr := conn.RemoteAddr()
31
-
32
-	encKey, encIV := deriveKeys(cipherPurposeClient, req, resp, localAddr, remoteAddr, secret)
33
-	decKey, decIV := deriveKeys(cipherPurposeServer, req, resp, localAddr, remoteAddr, secret)
34
-
35
-	enc, _ := makeEncrypterDecrypter(encKey, encIV)
36
-	_, dec := makeEncrypterDecrypter(decKey, decIV)
37
-
38
-	return NewBlockCipher(conn, enc, dec)
39
-}
40
-
41
-func deriveKeys(purpose cipherPurpose, req *rpc.NonceRequest, resp *rpc.NonceResponse,
42
-	client, remote *net.TCPAddr, secret []byte) ([]byte, []byte) {
43
-	message := bytes.Buffer{}
44
-	message.Write(resp.Nonce)   // nolint: gosec
45
-	message.Write(req.Nonce)    // nolint: gosec
46
-	message.Write(req.CryptoTS) // nolint: gosec
47
-
48
-	clientIPv4 := emptyIP[:]
49
-	serverIPv4 := emptyIP[:]
50
-	if client.IP.To4() != nil {
51
-		clientIPv4 = utils.ReverseBytes(client.IP.To4())
52
-		serverIPv4 = utils.ReverseBytes(remote.IP.To4())
53
-	}
54
-	message.Write(serverIPv4) // nolint: gosec
55
-
56
-	var port [2]byte
57
-	binary.LittleEndian.PutUint16(port[:], uint16(client.Port))
58
-	message.Write(port[:]) // nolint: gosec
59
-
60
-	switch purpose {
61
-	case cipherPurposeClient:
62
-		message.WriteString("CLIENT") // nolint: gosec
63
-	case cipherPurposeServer:
64
-		message.WriteString("SERVER") // nolint: gosec
65
-	default:
66
-		panic("Unexpected cipher purpose")
67
-	}
68
-
69
-	message.Write(clientIPv4) // nolint: gosec
70
-	binary.LittleEndian.PutUint16(port[:], uint16(remote.Port))
71
-	message.Write(port[:])    // nolint: gosec
72
-	message.Write(secret)     // nolint: gosec
73
-	message.Write(resp.Nonce) // nolint: gosec
74
-
75
-	if client.IP.To4() == nil {
76
-		message.Write(client.IP.To16()) // nolint: gosec
77
-		message.Write(remote.IP.To16()) // nolint: gosec
78
-	}
79
-	message.Write(req.Nonce) // nolint: gosec
80
-
81
-	data := message.Bytes()
82
-	md5sum := md5.Sum(data[1:]) // nolint: gas
83
-	sha1sum := sha1.Sum(data)   // nolint: gosec
84
-
85
-	key := append(md5sum[:12], sha1sum[:]...)
86
-	iv := md5.Sum(data[2:]) // nolint: gas
87
-
88
-	return key, iv[:]
89
-}
90
-
91
-func makeEncrypterDecrypter(key, iv []byte) (cipher.BlockMode, cipher.BlockMode) {
92
-	block, err := aes.NewCipher(key)
93
-	if err != nil {
94
-		panic(err)
95
-	}
96
-
97
-	return cipher.NewCBCEncrypter(block, iv), cipher.NewCBCDecrypter(block, iv)
98
-}

+ 0
- 161
_wrappers/mtproto_frame.go Просмотреть файл

@@ -1,161 +0,0 @@
1
-package wrappers
2
-
3
-import (
4
-	"bytes"
5
-	"crypto/aes"
6
-	"encoding/binary"
7
-	"hash/crc32"
8
-	"io"
9
-	"io/ioutil"
10
-	"net"
11
-
12
-	"github.com/juju/errors"
13
-	"go.uber.org/zap"
14
-)
15
-
16
-const (
17
-	mtprotoFrameMinMessageLength = 12
18
-	mtprotoFrameMaxMessageLength = 16777216
19
-)
20
-
21
-var mtprotoFramePadding = []byte{0x04, 0x00, 0x00, 0x00}
22
-
23
-// MTProtoFrame is a wrapper which converts written data to the MTProtoFrame.
24
-// The format of the frame:
25
-//
26
-// [ MSGLEN(4) | SEQNO(4) | MSG(...) | CRC32(4) | PADDING(4*x) ]
27
-//
28
-// MSGLEN is the length of the message + len of seqno and msglen.
29
-// SEQNO is the number of frame in the receive/send sequence. If client
30
-//   sends a message with SeqNo 18, it has to receive message with SeqNo 18.
31
-// MSG is the data which has to be written
32
-// CRC32 is the CRC32 checksum of MSGLEN + SEQNO + MSG
33
-// PADDING is custom padding schema to complete frame length to such that
34
-//    len(frame) % 16 == 0
35
-type MTProtoFrame struct {
36
-	conn   StreamReadWriteCloser
37
-	logger *zap.SugaredLogger
38
-
39
-	readSeqNo  int32
40
-	writeSeqNo int32
41
-}
42
-
43
-func (m *MTProtoFrame) Read() ([]byte, error) { // nolint: gocyclo
44
-	buf := &bytes.Buffer{}
45
-	sum := crc32.NewIEEE()
46
-	writer := io.MultiWriter(buf, sum)
47
-
48
-	for {
49
-		buf.Reset()
50
-		sum.Reset()
51
-		if _, err := io.CopyN(writer, m.conn, 4); err != nil {
52
-			return nil, errors.Annotate(err, "Cannot read frame padding")
53
-		}
54
-		if !bytes.Equal(buf.Bytes(), mtprotoFramePadding) {
55
-			break
56
-		}
57
-	}
58
-
59
-	messageLength := binary.LittleEndian.Uint32(buf.Bytes())
60
-	m.logger.Debugw("Read MTProto frame",
61
-		"messageLength", messageLength,
62
-		"sequence_number", m.readSeqNo,
63
-	)
64
-	if messageLength%4 != 0 || messageLength < mtprotoFrameMinMessageLength ||
65
-		messageLength > mtprotoFrameMaxMessageLength {
66
-		return nil, errors.Errorf("Incorrect frame message length %d", messageLength)
67
-	}
68
-
69
-	buf.Reset()
70
-	buf.Grow(int(messageLength) - 4 - 4)
71
-	if _, err := io.CopyN(writer, m.conn, int64(messageLength)-4-4); err != nil {
72
-		return nil, errors.Annotate(err, "Cannot read the message frame")
73
-	}
74
-
75
-	var seqNo int32
76
-	binary.Read(buf, binary.LittleEndian, &seqNo) // nolint: errcheck, gosec
77
-	if seqNo != m.readSeqNo {
78
-		return nil, errors.Errorf("Unexpected sequence number %d (wait for %d)", seqNo, m.readSeqNo)
79
-	}
80
-
81
-	data, _ := ioutil.ReadAll(buf) // nolint: gosec
82
-	buf.Reset()
83
-	// write to buf, not to writer. This is because we are going to fetch
84
-	// crc32 checksum.
85
-	if _, err := io.CopyN(buf, m.conn, 4); err != nil {
86
-		return nil, errors.Annotate(err, "Cannot read checksum")
87
-	}
88
-
89
-	checksum := binary.LittleEndian.Uint32(buf.Bytes())
90
-	if checksum != sum.Sum32() {
91
-		return nil, errors.Errorf("CRC32 checksum mismatch. Wait for %d, got %d", sum.Sum32(), checksum)
92
-	}
93
-
94
-	m.logger.Debugw("Read MTProto frame",
95
-		"messageLength", messageLength,
96
-		"sequence_number", m.readSeqNo,
97
-		"dataLength", len(data),
98
-		"checksum", checksum,
99
-	)
100
-	m.readSeqNo++
101
-
102
-	return data, nil
103
-}
104
-
105
-func (m *MTProtoFrame) Write(p []byte) (int, error) {
106
-	messageLength := 4 + 4 + len(p) + 4
107
-	paddingLength := (aes.BlockSize - messageLength%aes.BlockSize) % aes.BlockSize
108
-
109
-	buf := &bytes.Buffer{}
110
-	buf.Grow(messageLength + paddingLength)
111
-
112
-	binary.Write(buf, binary.LittleEndian, uint32(messageLength)) // nolint: errcheck, gosec
113
-	binary.Write(buf, binary.LittleEndian, m.writeSeqNo)          // nolint: errcheck, gosec
114
-	buf.Write(p)                                                  // nolint: gosec
115
-
116
-	checksum := crc32.ChecksumIEEE(buf.Bytes())
117
-	binary.Write(buf, binary.LittleEndian, checksum)              // nolint: errcheck, gosec
118
-	buf.Write(bytes.Repeat(mtprotoFramePadding, paddingLength/4)) // nolint: gosec
119
-
120
-	m.logger.Debugw("Write MTProto frame",
121
-		"length", len(p),
122
-		"sequence_number", m.writeSeqNo,
123
-		"crc32", checksum,
124
-		"frame_length", buf.Len(),
125
-	)
126
-	m.writeSeqNo++
127
-
128
-	_, err := m.conn.Write(buf.Bytes())
129
-
130
-	return len(p), err
131
-}
132
-
133
-// Logger returns an instance of the logger for this wrapper.
134
-func (m *MTProtoFrame) Logger() *zap.SugaredLogger {
135
-	return m.logger
136
-}
137
-
138
-// LocalAddr returns local address of the underlying net.Conn.
139
-func (m *MTProtoFrame) LocalAddr() *net.TCPAddr {
140
-	return m.conn.LocalAddr()
141
-}
142
-
143
-// RemoteAddr returns remote address of the underlying net.Conn.
144
-func (m *MTProtoFrame) RemoteAddr() *net.TCPAddr {
145
-	return m.conn.RemoteAddr()
146
-}
147
-
148
-// Close closes underlying net.Conn instance.
149
-func (m *MTProtoFrame) Close() error {
150
-	return m.conn.Close()
151
-}
152
-
153
-// NewMTProtoFrame creates new PacketWrapper for underlying connection.
154
-func NewMTProtoFrame(conn StreamReadWriteCloser, seqNo int32) PacketReadWriteCloser {
155
-	return &MTProtoFrame{
156
-		conn:       conn,
157
-		logger:     conn.Logger().Named("mtproto-frame"),
158
-		readSeqNo:  seqNo,
159
-		writeSeqNo: seqNo,
160
-	}
161
-}

+ 0
- 117
_wrappers/mtproto_intermediate.go Просмотреть файл

@@ -1,117 +0,0 @@
1
-package wrappers
2
-
3
-import (
4
-	"bytes"
5
-	"encoding/binary"
6
-	"io"
7
-	"net"
8
-
9
-	"github.com/juju/errors"
10
-	"go.uber.org/zap"
11
-
12
-	"github.com/9seconds/mtg/mtproto"
13
-)
14
-
15
-const mtprotoIntermediateQuickAckLength = 0x80000000
16
-
17
-// MTProtoIntermediate presents intermediate connection between client
18
-// and Telegram.
19
-type MTProtoIntermediate struct {
20
-	conn   StreamReadWriteCloser
21
-	opts   *mtproto.ConnectionOpts
22
-	logger *zap.SugaredLogger
23
-
24
-	readCounter  uint32
25
-	writeCounter uint32
26
-}
27
-
28
-func (m *MTProtoIntermediate) Read() ([]byte, error) {
29
-	defer func() {
30
-		m.readCounter++
31
-	}()
32
-
33
-	m.logger.Debugw("Read packet",
34
-		"simple_ack", m.opts.ReadHacks.SimpleAck,
35
-		"quick_ack", m.opts.ReadHacks.QuickAck,
36
-		"counter", m.readCounter,
37
-	)
38
-
39
-	buf := &bytes.Buffer{}
40
-	buf.Grow(4)
41
-
42
-	if _, err := io.CopyN(buf, m.conn, 4); err != nil {
43
-		return nil, errors.Annotate(err, "Cannot read message length")
44
-	}
45
-	length := binary.LittleEndian.Uint32(buf.Bytes())
46
-
47
-	m.logger.Debugw("Packet message length",
48
-		"simple_ack", m.opts.ReadHacks.SimpleAck,
49
-		"quick_ack", m.opts.ReadHacks.QuickAck,
50
-		"counter", m.readCounter,
51
-		"length", length,
52
-	)
53
-
54
-	if length > mtprotoIntermediateQuickAckLength {
55
-		m.opts.ReadHacks.QuickAck = true
56
-		length -= mtprotoIntermediateQuickAckLength
57
-	}
58
-
59
-	buf.Reset()
60
-	buf.Grow(int(length))
61
-	if _, err := io.CopyN(buf, m.conn, int64(length)); err != nil {
62
-		return nil, errors.Annotate(err, "Cannot read the message")
63
-	}
64
-
65
-	return buf.Bytes()[:length], nil
66
-}
67
-
68
-func (m *MTProtoIntermediate) Write(p []byte) (int, error) {
69
-	defer func() {
70
-		m.writeCounter++
71
-	}()
72
-
73
-	m.logger.Debugw("Write packet",
74
-		"simple_ack", m.opts.WriteHacks.SimpleAck,
75
-		"quick_ack", m.opts.WriteHacks.QuickAck,
76
-		"counter", m.writeCounter,
77
-	)
78
-
79
-	if m.opts.WriteHacks.SimpleAck {
80
-		return m.conn.Write(p)
81
-	}
82
-
83
-	var length [4]byte
84
-	binary.LittleEndian.PutUint32(length[:], uint32(len(p)))
85
-
86
-	return m.conn.Write(append(length[:], p...))
87
-}
88
-
89
-// Logger returns an instance of the logger for this wrapper.
90
-func (m *MTProtoIntermediate) Logger() *zap.SugaredLogger {
91
-	return m.logger
92
-}
93
-
94
-// LocalAddr returns local address of the underlying net.Conn.
95
-func (m *MTProtoIntermediate) LocalAddr() *net.TCPAddr {
96
-	return m.conn.LocalAddr()
97
-}
98
-
99
-// RemoteAddr returns remote address of the underlying net.Conn.
100
-func (m *MTProtoIntermediate) RemoteAddr() *net.TCPAddr {
101
-	return m.conn.RemoteAddr()
102
-}
103
-
104
-// Close closes underlying net.Conn instance.
105
-func (m *MTProtoIntermediate) Close() error {
106
-	return m.conn.Close()
107
-}
108
-
109
-// NewMTProtoIntermediate creates new PacketWrapper for intermediate
110
-// client connection.
111
-func NewMTProtoIntermediate(conn StreamReadWriteCloser, opts *mtproto.ConnectionOpts) PacketReadWriteCloser {
112
-	return &MTProtoIntermediate{
113
-		conn:   conn,
114
-		logger: conn.Logger().Named("mtproto-intermediate"),
115
-		opts:   opts,
116
-	}
117
-}

+ 0
- 74
_wrappers/mtproto_intermediate_secure.go Просмотреть файл

@@ -1,74 +0,0 @@
1
-package wrappers
2
-
3
-import (
4
-	"bytes"
5
-	"encoding/binary"
6
-	"math/rand"
7
-
8
-	"github.com/9seconds/mtg/mtproto"
9
-)
10
-
11
-// MTProtoIntermediateSecure is an extension of MTProtoIntermediate
12
-// mode which supports random paddings (socalled 'secure mode' or
13
-// 'dd-secrets').
14
-type MTProtoIntermediateSecure struct {
15
-	MTProtoIntermediate
16
-}
17
-
18
-func (m *MTProtoIntermediateSecure) Read() ([]byte, error) {
19
-	data, err := m.MTProtoIntermediate.Read()
20
-	if err != nil {
21
-		return nil, err
22
-	}
23
-	length := len(data) - (len(data) % 4)
24
-
25
-	return data[:length], nil
26
-}
27
-
28
-func (m *MTProtoIntermediateSecure) Write(p []byte) (int, error) {
29
-	defer func() {
30
-		m.writeCounter++
31
-	}()
32
-
33
-	m.logger.Debugw("Write packet",
34
-		"simple_ack", m.opts.WriteHacks.SimpleAck,
35
-		"quick_ack", m.opts.WriteHacks.QuickAck,
36
-		"counter", m.writeCounter,
37
-	)
38
-
39
-	if m.opts.WriteHacks.SimpleAck {
40
-		return m.conn.Write(p)
41
-	}
42
-
43
-	buf := &bytes.Buffer{}
44
-	paddingLength := rand.Intn(4)
45
-	buf.Grow(4 + len(p) + paddingLength)
46
-
47
-	binary.Write(buf, binary.LittleEndian, uint32(len(p)+paddingLength)) // nolint: errcheck, gosec
48
-	buf.Write(p)                                                         // nolint: gosec
49
-	buf.Write(make([]byte, paddingLength))                               // nolint: gosec
50
-
51
-	m.logger.Debugw("Write packet with padding",
52
-		"simple_ack", m.opts.WriteHacks.SimpleAck,
53
-		"quick_ack", m.opts.WriteHacks.QuickAck,
54
-		"counter", m.writeCounter,
55
-		"padding_length", paddingLength,
56
-		"length", len(p),
57
-	)
58
-
59
-	_, err := m.conn.Write(buf.Bytes())
60
-
61
-	return len(p), err
62
-}
63
-
64
-// NewMTProtoIntermediateSecure create new instance of
65
-// MTProtoIntermediateSecure instance.
66
-func NewMTProtoIntermediateSecure(conn StreamReadWriteCloser, opts *mtproto.ConnectionOpts) PacketReadWriteCloser {
67
-	return &MTProtoIntermediateSecure{
68
-		MTProtoIntermediate: MTProtoIntermediate{
69
-			conn:   conn,
70
-			logger: conn.Logger().Named("mtproto-intermediate-secure"),
71
-			opts:   opts,
72
-		},
73
-	}
74
-}

+ 0
- 165
_wrappers/mtproto_proxy.go Просмотреть файл

@@ -1,165 +0,0 @@
1
-package wrappers
2
-
3
-import (
4
-	"bytes"
5
-	"fmt"
6
-	"net"
7
-
8
-	"github.com/juju/errors"
9
-	"go.uber.org/zap"
10
-
11
-	"github.com/9seconds/mtg/mtproto"
12
-	"github.com/9seconds/mtg/mtproto/rpc"
13
-)
14
-
15
-// MTProtoProxy is a wrapper which creates/reads RPC responses from Telegram.
16
-type MTProtoProxy struct {
17
-	conn   PacketReadWriteCloser
18
-	req    *rpc.ProxyRequest
19
-	logger *zap.SugaredLogger
20
-
21
-	readCounter  uint32
22
-	writeCounter uint32
23
-}
24
-
25
-func (m *MTProtoProxy) Read() ([]byte, error) {
26
-	defer func() {
27
-		m.readCounter++
28
-	}()
29
-
30
-	m.logger.Debugw("Read packet",
31
-		"counter", m.readCounter,
32
-		"simple_ack", m.req.Options.WriteHacks.SimpleAck,
33
-		"quick_ack", m.req.Options.WriteHacks.QuickAck,
34
-	)
35
-
36
-	packet, err := m.conn.Read()
37
-	if err != nil {
38
-		return nil, errors.Annotate(err, "Cannot read packet")
39
-	}
40
-
41
-	m.logger.Debugw("Read packet length",
42
-		"counter", m.readCounter,
43
-		"simple_ack", m.req.Options.WriteHacks.SimpleAck,
44
-		"quick_ack", m.req.Options.WriteHacks.QuickAck,
45
-		"length", len(packet),
46
-	)
47
-
48
-	if len(packet) < 4 {
49
-		return nil, errors.Annotate(err, "Incorrect packet length")
50
-	}
51
-
52
-	tag, packet := packet[:4], packet[4:]
53
-	switch {
54
-	case bytes.Equal(tag, rpc.TagProxyAns):
55
-		return m.readProxyAns(packet)
56
-	case bytes.Equal(tag, rpc.TagSimpleAck):
57
-		return m.readSimpleAck(packet)
58
-	case bytes.Equal(tag, rpc.TagCloseExt):
59
-		return m.readCloseExt()
60
-	}
61
-
62
-	return nil, errors.Errorf("Unknown RPC answer %v", tag)
63
-}
64
-
65
-func (m *MTProtoProxy) readProxyAns(data []byte) ([]byte, error) {
66
-	if len(data) < 12 {
67
-		return nil, errors.Errorf("Incorrect data of proxy answer: %d", len(data))
68
-	}
69
-	data = data[12:]
70
-
71
-	m.logger.Debugw("Read RPC_PROXY_ANS",
72
-		"counter", m.readCounter,
73
-		"length", len(data),
74
-	)
75
-
76
-	return data, nil
77
-}
78
-
79
-func (m *MTProtoProxy) readSimpleAck(data []byte) ([]byte, error) {
80
-	if len(data) != 12 {
81
-		return nil, errors.Errorf("Incorrect data of simple ack: %d", len(data))
82
-	}
83
-	data = data[8:12]
84
-	m.req.Options.WriteHacks.SimpleAck = true
85
-
86
-	m.logger.Debugw("Read RPC_SIMPLE_ACK",
87
-		"counter", m.readCounter,
88
-		"length", len(data),
89
-	)
90
-
91
-	return data, nil
92
-}
93
-
94
-func (m *MTProtoProxy) readCloseExt() ([]byte, error) {
95
-	m.logger.Debugw("Read RPC_CLOSE_EXT", "counter", m.readCounter)
96
-
97
-	return nil, errors.New("Connection has been closed remotely by RPC call")
98
-}
99
-
100
-func (m *MTProtoProxy) Write(p []byte) (int, error) {
101
-	defer func() {
102
-		m.writeCounter++
103
-	}()
104
-
105
-	m.logger.Debugw("Write packet",
106
-		"length", len(p),
107
-		"counter", m.writeCounter,
108
-		"simple_ack", m.req.Options.ReadHacks.SimpleAck,
109
-		"quick_ack", m.req.Options.ReadHacks.QuickAck,
110
-	)
111
-
112
-	header, flags := m.req.MakeHeader(p)
113
-	if ce := m.logger.Desugar().Check(zap.DebugLevel, "RPC_PROXY_REQ header"); ce != nil {
114
-		ce.Write(
115
-			zap.Int("length", len(p)),
116
-			zap.Uint32("counter", m.writeCounter),
117
-			zap.Bool("simple_ack", m.req.Options.ReadHacks.QuickAck),
118
-			zap.Bool("quick_ack", m.req.Options.ReadHacks.SimpleAck),
119
-			zap.String("header", fmt.Sprintf("%v", header.Bytes())),
120
-			zap.Stringer("flags", flags),
121
-		)
122
-	}
123
-	header.Write(p) // nolint: gosec
124
-
125
-	if _, err := m.conn.Write(header.Bytes()); err != nil {
126
-		return 0, err
127
-	}
128
-
129
-	return len(p), nil
130
-}
131
-
132
-// Logger returns an instance of the logger for this wrapper.
133
-func (m *MTProtoProxy) Logger() *zap.SugaredLogger {
134
-	return m.logger
135
-}
136
-
137
-// LocalAddr returns local address of the underlying net.Conn.
138
-func (m *MTProtoProxy) LocalAddr() *net.TCPAddr {
139
-	return m.conn.LocalAddr()
140
-}
141
-
142
-// RemoteAddr returns remote address of the underlying net.Conn.
143
-func (m *MTProtoProxy) RemoteAddr() *net.TCPAddr {
144
-	return m.conn.RemoteAddr()
145
-}
146
-
147
-// Close closes underlying net.Conn instance.
148
-func (m *MTProtoProxy) Close() error {
149
-	return m.conn.Close()
150
-}
151
-
152
-// NewMTProtoProxy creates new RPC wrapper.
153
-func NewMTProtoProxy(conn PacketReadWriteCloser, connOpts *mtproto.ConnectionOpts,
154
-	adTag []byte) (PacketReadWriteCloser, error) {
155
-	req, err := rpc.NewProxyRequest(connOpts.ClientAddr, conn.LocalAddr(), connOpts, adTag)
156
-	if err != nil {
157
-		return nil, errors.Annotate(err, "Cannot create new RPC proxy request")
158
-	}
159
-
160
-	return &MTProtoProxy{
161
-		conn:   conn,
162
-		logger: conn.Logger().Named("mtproto-proxy"),
163
-		req:    req,
164
-	}, nil
165
-}

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

@@ -1,73 +0,0 @@
1
-package wrappers
2
-
3
-import (
4
-	"bytes"
5
-	"crypto/cipher"
6
-	"net"
7
-
8
-	"github.com/juju/errors"
9
-	"go.uber.org/zap"
10
-)
11
-
12
-// StreamCipher is a wrapper which encrypts/decrypts stream with AES-CTR
13
-// (as a part of obfuscated2 protocol).
14
-type StreamCipher struct {
15
-	encryptor cipher.Stream
16
-	decryptor cipher.Stream
17
-	conn      StreamReadWriteCloser
18
-	logger    *zap.SugaredLogger
19
-}
20
-
21
-func (s *StreamCipher) Read(p []byte) (int, error) {
22
-	n, err := s.conn.Read(p)
23
-	if err != nil {
24
-		return 0, errors.Annotate(err, "Cannot read stream ciphered data")
25
-	}
26
-	s.decryptor.XORKeyStream(p, p[:n])
27
-
28
-	return n, nil
29
-}
30
-
31
-func (s *StreamCipher) Write(p []byte) (int, error) {
32
-	buf := streamCipherBufferPool.Get().(*bytes.Buffer)
33
-	defer streamCipherBufferPool.Put(buf)
34
-
35
-	buf.Reset()
36
-	buf.Grow(len(p))
37
-	buf.Write(p) // nolint: gosec
38
-
39
-	data := buf.Bytes()
40
-	s.encryptor.XORKeyStream(data, data)
41
-
42
-	return s.conn.Write(data)
43
-}
44
-
45
-// Logger returns an instance of the logger for this wrapper.
46
-func (s *StreamCipher) Logger() *zap.SugaredLogger {
47
-	return s.logger
48
-}
49
-
50
-// LocalAddr returns local address of the underlying net.Conn.
51
-func (s *StreamCipher) LocalAddr() *net.TCPAddr {
52
-	return s.conn.LocalAddr()
53
-}
54
-
55
-// RemoteAddr returns remote address of the underlying net.Conn.
56
-func (s *StreamCipher) RemoteAddr() *net.TCPAddr {
57
-	return s.conn.RemoteAddr()
58
-}
59
-
60
-// Close closes underlying net.Conn instance.
61
-func (s *StreamCipher) Close() error {
62
-	return s.conn.Close()
63
-}
64
-
65
-// NewStreamCipher creates new stream cipher wrapper.
66
-func NewStreamCipher(conn StreamReadWriteCloser, encryptor, decryptor cipher.Stream) StreamReadWriteCloser {
67
-	return &StreamCipher{
68
-		conn:      conn,
69
-		logger:    conn.Logger().Named("stream-cipher"),
70
-		encryptor: encryptor,
71
-		decryptor: decryptor,
72
-	}
73
-}

+ 0
- 14
_wrappers/streamcipher_pool.go Просмотреть файл

@@ -1,14 +0,0 @@
1
-package wrappers
2
-
3
-import (
4
-	"bytes"
5
-	"sync"
6
-)
7
-
8
-var (
9
-	streamCipherBufferPool = sync.Pool{
10
-		New: func() interface{} {
11
-			return &bytes.Buffer{}
12
-		},
13
-	}
14
-)

+ 0
- 111
_wrappers/wrap.go Просмотреть файл

@@ -1,111 +0,0 @@
1
-package wrappers
2
-
3
-import (
4
-	"io"
5
-	"net"
6
-
7
-	"go.uber.org/zap"
8
-)
9
-
10
-// Wrap is a base interface for all wrappers in this package.
11
-type Wrap interface {
12
-	Logger() *zap.SugaredLogger
13
-	LocalAddr() *net.TCPAddr
14
-	RemoteAddr() *net.TCPAddr
15
-}
16
-
17
-// Writer is a base interface for writers of this package.
18
-type Writer interface {
19
-	io.Writer
20
-	Wrap
21
-}
22
-
23
-// Closer is a base interface for wrappers of this package which can
24
-// close connections.
25
-type Closer interface {
26
-	io.Closer
27
-	Wrap
28
-}
29
-
30
-// WriteCloser is a base interface for wrappers of this package which
31
-// can write to and close connections.
32
-type WriteCloser interface {
33
-	io.Closer
34
-	Writer
35
-}
36
-
37
-// StreamReader is a base interface for wrappers which can read from the
38
-// stream.
39
-type StreamReader interface {
40
-	io.Reader
41
-	Wrap
42
-}
43
-
44
-// StreamReadCloser is a base interface for wrappers which can read from
45
-// and close the connections.
46
-type StreamReadCloser interface {
47
-	io.Closer
48
-	StreamReader
49
-}
50
-
51
-// StreamReadWriter is a base interface for wrappers which can read from
52
-// and write to the connections.
53
-type StreamReadWriter interface {
54
-	io.Writer
55
-	StreamReader
56
-}
57
-
58
-// StreamWriteCloser is a base interface for wrappers which can write to
59
-// and close the connections.
60
-type StreamWriteCloser interface {
61
-	io.WriteCloser
62
-	Wrap
63
-}
64
-
65
-// StreamReadWriteCloser is a base interface for stream processors.
66
-type StreamReadWriteCloser interface {
67
-	io.Closer
68
-	StreamReadWriter
69
-}
70
-
71
-// PacketReader is a base interface for wrappers which reads 'packets'.
72
-// packets are atoms so you either get a packet or you get an error You
73
-// cannot resume reading from packet.
74
-type PacketReader interface {
75
-	Read() ([]byte, error)
76
-	Wrap
77
-}
78
-
79
-// PacketWriter is a base interface for wrappers which can write packets.
80
-type PacketWriter interface {
81
-	io.Writer
82
-	Wrap
83
-}
84
-
85
-// PacketReadWriter is a base interface for wrappers which can read from
86
-// and write packets.
87
-type PacketReadWriter interface {
88
-	io.Writer
89
-	PacketReader
90
-}
91
-
92
-// PacketReadCloser is a base interface for wrappers which can read
93
-// packets and close the connection.
94
-type PacketReadCloser interface {
95
-	io.Closer
96
-	PacketReader
97
-}
98
-
99
-// PacketWriteCloser is a base interface for wrappers which can write
100
-// packets and close the connection.
101
-type PacketWriteCloser interface {
102
-	io.Writer
103
-	io.Closer
104
-	Wrap
105
-}
106
-
107
-// PacketReadWriteCloser is a base interface for packet processors.
108
-type PacketReadWriteCloser interface {
109
-	io.Closer
110
-	PacketReadWriter
111
-}

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