Преглед изворни кода

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

Correct support of secure padding
tags/0.10
Sergey Arkhipov пре 7 година
родитељ
комит
d0ae470c73
No account linked to committer's email address

+ 9
- 2
client/middle.go Прегледај датотеку

@@ -17,9 +17,16 @@ func MiddleInit(socket net.Conn, connID string, conf *config.Config) (wrappers.W
17 17
 	}
18 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 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 32
 	opts.ConnectionProto = mtproto.ConnectionProtocolIPv4

+ 31
- 8
config/config.go Прегледај датотеку

@@ -18,8 +18,9 @@ const (
18 18
 
19 19
 // Config represents common configuration of mtg.
20 20
 type Config struct {
21
-	Debug   bool
22
-	Verbose bool
21
+	Debug      bool
22
+	Verbose    bool
23
+	SecureMode bool
23 24
 
24 25
 	BindPort       uint16
25 26
 	PublicIPv4Port uint16
@@ -45,8 +46,9 @@ type URLs struct {
45 46
 
46 47
 // IPURLs contains links to both ipv4 and ipv6 of the proxy.
47 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 54
 // BindAddr returns connection for this server to bind to.
@@ -65,15 +67,32 @@ func (c *Config) UseMiddleProxy() bool {
65 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 85
 // GetURLs returns configured IPURLs instance with links to this server.
69 86
 func (c *Config) GetURLs() IPURLs {
70 87
 	urls := IPURLs{}
88
+	secret := c.SecretString()
71 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 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 97
 	return urls
79 98
 }
@@ -91,8 +110,11 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo
91 110
 	publicIPv6 net.IP, publicIPv6Port uint16,
92 111
 	statsIP net.IP, statsPort uint16,
93 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 118
 		return nil, errors.New("Telegram demands secret of length 32")
97 119
 	}
98 120
 	secretBytes, err := hex.DecodeString(secret)
@@ -149,6 +171,7 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo
149 171
 		StatsPort:      statsPort,
150 172
 		Secret:         secretBytes,
151 173
 		AdTag:          adTagBytes,
174
+		SecureMode:     secureMode,
152 175
 	}
153 176
 
154 177
 	return conf, nil

+ 2
- 3
config/urls.go Прегледај датотеку

@@ -1,17 +1,16 @@
1 1
 package config
2 2
 
3 3
 import (
4
-	"encoding/hex"
5 4
 	"net"
6 5
 	"net/url"
7 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 10
 	values := url.Values{}
12 11
 	values.Set("server", addr.String())
13 12
 	values.Set("port", strconv.Itoa(int(port)))
14
-	values.Set("secret", hex.EncodeToString(secret))
13
+	values.Set("secret", secret)
15 14
 
16 15
 	urls.TG = makeTGURL(values)
17 16
 	urls.TMe = makeTMeURL(values)

+ 4
- 0
mtproto/rpc/proxy_flags.go Прегледај датотеку

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

+ 7
- 2
mtproto/rpc/proxy_request.go Прегледај датотеку

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

+ 1
- 5
wrappers/mtproto_intermediate.go Прегледај датотеку

@@ -62,10 +62,6 @@ func (m *MTProtoIntermediate) Read() ([]byte, error) {
62 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 65
 	return buf.Bytes()[:length], nil
70 66
 }
71 67
 
@@ -80,7 +76,7 @@ func (m *MTProtoIntermediate) Write(p []byte) (int, error) {
80 76
 		"counter", m.writeCounter,
81 77
 	)
82 78
 
83
-	if m.opts.ReadHacks.SimpleAck {
79
+	if m.opts.WriteHacks.SimpleAck {
84 80
 		return m.conn.Write(p)
85 81
 	}
86 82
 

+ 74
- 0
wrappers/mtproto_intermediate_secure.go Прегледај датотеку

@@ -0,0 +1,74 @@
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
+}

Loading…
Откажи
Сачувај