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

Merge pull request #22 from 9seconds/secure-padding

Correct support of secure padding
tags/0.10
Sergey Arkhipov 7 лет назад
Родитель
Сommit
d0ae470c73
Аккаунт пользователя с таким Email не найден

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

17
 	}
17
 	}
18
 	connStream := conn.(wrappers.StreamReadWriteCloser)
18
 	connStream := conn.(wrappers.StreamReadWriteCloser)
19
 
19
 
20
-	newConn := wrappers.NewMTProtoAbridged(connStream, opts)
21
-	if opts.ConnectionType != mtproto.ConnectionTypeAbridged {
20
+	var newConn wrappers.PacketReadWriteCloser
21
+	switch opts.ConnectionType {
22
+	case mtproto.ConnectionTypeAbridged:
23
+		newConn = wrappers.NewMTProtoAbridged(connStream, opts)
24
+	case mtproto.ConnectionTypeIntermediate:
22
 		newConn = wrappers.NewMTProtoIntermediate(connStream, opts)
25
 		newConn = wrappers.NewMTProtoIntermediate(connStream, opts)
26
+	case mtproto.ConnectionTypeSecure:
27
+		newConn = wrappers.NewMTProtoIntermediateSecure(connStream, opts)
28
+	default:
29
+		panic("Unknown connection type")
23
 	}
30
 	}
24
 
31
 
25
 	opts.ConnectionProto = mtproto.ConnectionProtocolIPv4
32
 	opts.ConnectionProto = mtproto.ConnectionProtocolIPv4

+ 31
- 8
config/config.go Просмотреть файл

18
 
18
 
19
 // Config represents common configuration of mtg.
19
 // Config represents common configuration of mtg.
20
 type Config struct {
20
 type Config struct {
21
-	Debug   bool
22
-	Verbose bool
21
+	Debug      bool
22
+	Verbose    bool
23
+	SecureMode bool
23
 
24
 
24
 	BindPort       uint16
25
 	BindPort       uint16
25
 	PublicIPv4Port uint16
26
 	PublicIPv4Port uint16
45
 
46
 
46
 // IPURLs contains links to both ipv4 and ipv6 of the proxy.
47
 // IPURLs contains links to both ipv4 and ipv6 of the proxy.
47
 type IPURLs struct {
48
 type IPURLs struct {
48
-	IPv4 URLs `json:"ipv4"`
49
-	IPv6 URLs `json:"ipv6"`
49
+	IPv4      URLs   `json:"ipv4"`
50
+	IPv6      URLs   `json:"ipv6"`
51
+	BotSecret string `json:"secret_for_mtproxybot"`
50
 }
52
 }
51
 
53
 
52
 // BindAddr returns connection for this server to bind to.
54
 // BindAddr returns connection for this server to bind to.
65
 	return len(c.AdTag) > 0
67
 	return len(c.AdTag) > 0
66
 }
68
 }
67
 
69
 
70
+// BotSecretString returns secret string which should work with MTProxybot.
71
+func (c *Config) BotSecretString() string {
72
+	return hex.EncodeToString(c.Secret)
73
+}
74
+
75
+// SecretString returns a secret in a form entered on the start of the
76
+// application.
77
+func (c *Config) SecretString() string {
78
+	secret := c.BotSecretString()
79
+	if c.SecureMode {
80
+		return "dd" + secret
81
+	}
82
+	return secret
83
+}
84
+
68
 // GetURLs returns configured IPURLs instance with links to this server.
85
 // GetURLs returns configured IPURLs instance with links to this server.
69
 func (c *Config) GetURLs() IPURLs {
86
 func (c *Config) GetURLs() IPURLs {
70
 	urls := IPURLs{}
87
 	urls := IPURLs{}
88
+	secret := c.SecretString()
71
 	if c.PublicIPv4 != nil {
89
 	if c.PublicIPv4 != nil {
72
-		urls.IPv4 = getURLs(c.PublicIPv4, c.PublicIPv4Port, c.Secret)
90
+		urls.IPv4 = getURLs(c.PublicIPv4, c.PublicIPv4Port, secret)
73
 	}
91
 	}
74
 	if c.PublicIPv6 != nil {
92
 	if c.PublicIPv6 != nil {
75
-		urls.IPv6 = getURLs(c.PublicIPv6, c.PublicIPv6Port, c.Secret)
93
+		urls.IPv6 = getURLs(c.PublicIPv6, c.PublicIPv6Port, secret)
76
 	}
94
 	}
95
+	urls.BotSecret = c.BotSecretString()
77
 
96
 
78
 	return urls
97
 	return urls
79
 }
98
 }
91
 	publicIPv6 net.IP, publicIPv6Port uint16,
110
 	publicIPv6 net.IP, publicIPv6Port uint16,
92
 	statsIP net.IP, statsPort uint16,
111
 	statsIP net.IP, statsPort uint16,
93
 	secret, adtag string) (*Config, error) {
112
 	secret, adtag string) (*Config, error) {
94
-	secret = strings.TrimPrefix(secret, "dd")
95
-	if len(secret) != 32 {
113
+	secureMode := false
114
+	if strings.HasPrefix(secret, "dd") && len(secret) == 34 {
115
+		secureMode = true
116
+		secret = strings.TrimPrefix(secret, "dd")
117
+	} else if len(secret) != 32 {
96
 		return nil, errors.New("Telegram demands secret of length 32")
118
 		return nil, errors.New("Telegram demands secret of length 32")
97
 	}
119
 	}
98
 	secretBytes, err := hex.DecodeString(secret)
120
 	secretBytes, err := hex.DecodeString(secret)
149
 		StatsPort:      statsPort,
171
 		StatsPort:      statsPort,
150
 		Secret:         secretBytes,
172
 		Secret:         secretBytes,
151
 		AdTag:          adTagBytes,
173
 		AdTag:          adTagBytes,
174
+		SecureMode:     secureMode,
152
 	}
175
 	}
153
 
176
 
154
 	return conf, nil
177
 	return conf, nil

+ 2
- 3
config/urls.go Просмотреть файл

1
 package config
1
 package config
2
 
2
 
3
 import (
3
 import (
4
-	"encoding/hex"
5
 	"net"
4
 	"net"
6
 	"net/url"
5
 	"net/url"
7
 	"strconv"
6
 	"strconv"
8
 )
7
 )
9
 
8
 
10
-func getURLs(addr net.IP, port uint16, secret []byte) (urls URLs) {
9
+func getURLs(addr net.IP, port uint16, secret string) (urls URLs) {
11
 	values := url.Values{}
10
 	values := url.Values{}
12
 	values.Set("server", addr.String())
11
 	values.Set("server", addr.String())
13
 	values.Set("port", strconv.Itoa(int(port)))
12
 	values.Set("port", strconv.Itoa(int(port)))
14
-	values.Set("secret", hex.EncodeToString(secret))
13
+	values.Set("secret", secret)
15
 
14
 
16
 	urls.TG = makeTGURL(values)
15
 	urls.TG = makeTGURL(values)
17
 	urls.TMe = makeTMeURL(values)
16
 	urls.TMe = makeTMeURL(values)

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

15
 	proxyRequestFlagsIntermediate                   = 0x20000000
15
 	proxyRequestFlagsIntermediate                   = 0x20000000
16
 	proxyRequestFlagsAbdridged                      = 0x40000000
16
 	proxyRequestFlagsAbdridged                      = 0x40000000
17
 	proxyRequestFlagsQuickAck                       = 0x80000000
17
 	proxyRequestFlagsQuickAck                       = 0x80000000
18
+	proxyRequestFlagsPad                            = 0x8000000
18
 )
19
 )
19
 
20
 
20
 var proxyRequestFlagsEncryptedPrefix [8]byte
21
 var proxyRequestFlagsEncryptedPrefix [8]byte
50
 	if r&proxyRequestFlagsQuickAck != 0 {
51
 	if r&proxyRequestFlagsQuickAck != 0 {
51
 		flags = append(flags, "QUICK_ACK")
52
 		flags = append(flags, "QUICK_ACK")
52
 	}
53
 	}
54
+	if r&proxyRequestFlagsPad != 0 {
55
+		flags = append(flags, "PAD")
56
+	}
53
 
57
 
54
 	return strings.Join(flags, " | ")
58
 	return strings.Join(flags, " | ")
55
 }
59
 }

+ 7
- 2
mtproto/rpc/proxy_request.go Просмотреть файл

67
 func NewProxyRequest(clientAddr, ownAddr *net.TCPAddr, opts *mtproto.ConnectionOpts, adTag []byte) (*ProxyRequest, error) {
67
 func NewProxyRequest(clientAddr, ownAddr *net.TCPAddr, opts *mtproto.ConnectionOpts, adTag []byte) (*ProxyRequest, error) {
68
 	flags := proxyRequestFlagsHasAdTag | proxyRequestFlagsMagic | proxyRequestFlagsExtMode2
68
 	flags := proxyRequestFlagsHasAdTag | proxyRequestFlagsMagic | proxyRequestFlagsExtMode2
69
 
69
 
70
-	if opts.ConnectionType == mtproto.ConnectionTypeAbridged {
70
+	switch opts.ConnectionType {
71
+	case mtproto.ConnectionTypeAbridged:
71
 		flags |= proxyRequestFlagsAbdridged
72
 		flags |= proxyRequestFlagsAbdridged
72
-	} else {
73
+	case mtproto.ConnectionTypeIntermediate:
73
 		flags |= proxyRequestFlagsIntermediate
74
 		flags |= proxyRequestFlagsIntermediate
75
+	case mtproto.ConnectionTypeSecure:
76
+		flags |= proxyRequestFlagsIntermediate | proxyRequestFlagsPad
77
+	default:
78
+		panic("Unknown connection type")
74
 	}
79
 	}
75
 
80
 
76
 	request := &ProxyRequest{
81
 	request := &ProxyRequest{

+ 1
- 5
wrappers/mtproto_intermediate.go Просмотреть файл

62
 		return nil, errors.Annotate(err, "Cannot read the message")
62
 		return nil, errors.Annotate(err, "Cannot read the message")
63
 	}
63
 	}
64
 
64
 
65
-	if length%4 != 0 {
66
-		length -= length % 4
67
-	}
68
-
69
 	return buf.Bytes()[:length], nil
65
 	return buf.Bytes()[:length], nil
70
 }
66
 }
71
 
67
 
80
 		"counter", m.writeCounter,
76
 		"counter", m.writeCounter,
81
 	)
77
 	)
82
 
78
 
83
-	if m.opts.ReadHacks.SimpleAck {
79
+	if m.opts.WriteHacks.SimpleAck {
84
 		return m.conn.Write(p)
80
 		return m.conn.Write(p)
85
 	}
81
 	}
86
 
82
 

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

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
48
+	buf.Write(p)
49
+	buf.Write(make([]byte, paddingLength))
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
+}

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