mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-09-01 16:01:55 +03:00
Merge pull request #22 from 9seconds/secure-padding
Correct support of secure padding
This commit is contained in:
+9
-2
@@ -17,9 +17,16 @@ func MiddleInit(socket net.Conn, connID string, conf *config.Config) (wrappers.W
|
||||
}
|
||||
connStream := conn.(wrappers.StreamReadWriteCloser)
|
||||
|
||||
newConn := wrappers.NewMTProtoAbridged(connStream, opts)
|
||||
if opts.ConnectionType != mtproto.ConnectionTypeAbridged {
|
||||
var newConn wrappers.PacketReadWriteCloser
|
||||
switch opts.ConnectionType {
|
||||
case mtproto.ConnectionTypeAbridged:
|
||||
newConn = wrappers.NewMTProtoAbridged(connStream, opts)
|
||||
case mtproto.ConnectionTypeIntermediate:
|
||||
newConn = wrappers.NewMTProtoIntermediate(connStream, opts)
|
||||
case mtproto.ConnectionTypeSecure:
|
||||
newConn = wrappers.NewMTProtoIntermediateSecure(connStream, opts)
|
||||
default:
|
||||
panic("Unknown connection type")
|
||||
}
|
||||
|
||||
opts.ConnectionProto = mtproto.ConnectionProtocolIPv4
|
||||
|
||||
+31
-8
@@ -18,8 +18,9 @@ const (
|
||||
|
||||
// Config represents common configuration of mtg.
|
||||
type Config struct {
|
||||
Debug bool
|
||||
Verbose bool
|
||||
Debug bool
|
||||
Verbose bool
|
||||
SecureMode bool
|
||||
|
||||
BindPort uint16
|
||||
PublicIPv4Port uint16
|
||||
@@ -45,8 +46,9 @@ type URLs struct {
|
||||
|
||||
// IPURLs contains links to both ipv4 and ipv6 of the proxy.
|
||||
type IPURLs struct {
|
||||
IPv4 URLs `json:"ipv4"`
|
||||
IPv6 URLs `json:"ipv6"`
|
||||
IPv4 URLs `json:"ipv4"`
|
||||
IPv6 URLs `json:"ipv6"`
|
||||
BotSecret string `json:"secret_for_mtproxybot"`
|
||||
}
|
||||
|
||||
// BindAddr returns connection for this server to bind to.
|
||||
@@ -65,15 +67,32 @@ func (c *Config) UseMiddleProxy() bool {
|
||||
return len(c.AdTag) > 0
|
||||
}
|
||||
|
||||
// BotSecretString returns secret string which should work with MTProxybot.
|
||||
func (c *Config) BotSecretString() string {
|
||||
return hex.EncodeToString(c.Secret)
|
||||
}
|
||||
|
||||
// SecretString returns a secret in a form entered on the start of the
|
||||
// application.
|
||||
func (c *Config) SecretString() string {
|
||||
secret := c.BotSecretString()
|
||||
if c.SecureMode {
|
||||
return "dd" + secret
|
||||
}
|
||||
return secret
|
||||
}
|
||||
|
||||
// GetURLs returns configured IPURLs instance with links to this server.
|
||||
func (c *Config) GetURLs() IPURLs {
|
||||
urls := IPURLs{}
|
||||
secret := c.SecretString()
|
||||
if c.PublicIPv4 != nil {
|
||||
urls.IPv4 = getURLs(c.PublicIPv4, c.PublicIPv4Port, c.Secret)
|
||||
urls.IPv4 = getURLs(c.PublicIPv4, c.PublicIPv4Port, secret)
|
||||
}
|
||||
if c.PublicIPv6 != nil {
|
||||
urls.IPv6 = getURLs(c.PublicIPv6, c.PublicIPv6Port, c.Secret)
|
||||
urls.IPv6 = getURLs(c.PublicIPv6, c.PublicIPv6Port, secret)
|
||||
}
|
||||
urls.BotSecret = c.BotSecretString()
|
||||
|
||||
return urls
|
||||
}
|
||||
@@ -91,8 +110,11 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo
|
||||
publicIPv6 net.IP, publicIPv6Port uint16,
|
||||
statsIP net.IP, statsPort uint16,
|
||||
secret, adtag string) (*Config, error) {
|
||||
secret = strings.TrimPrefix(secret, "dd")
|
||||
if len(secret) != 32 {
|
||||
secureMode := false
|
||||
if strings.HasPrefix(secret, "dd") && len(secret) == 34 {
|
||||
secureMode = true
|
||||
secret = strings.TrimPrefix(secret, "dd")
|
||||
} else if len(secret) != 32 {
|
||||
return nil, errors.New("Telegram demands secret of length 32")
|
||||
}
|
||||
secretBytes, err := hex.DecodeString(secret)
|
||||
@@ -149,6 +171,7 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo
|
||||
StatsPort: statsPort,
|
||||
Secret: secretBytes,
|
||||
AdTag: adTagBytes,
|
||||
SecureMode: secureMode,
|
||||
}
|
||||
|
||||
return conf, nil
|
||||
|
||||
+2
-3
@@ -1,17 +1,16 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func getURLs(addr net.IP, port uint16, secret []byte) (urls URLs) {
|
||||
func getURLs(addr net.IP, port uint16, secret string) (urls URLs) {
|
||||
values := url.Values{}
|
||||
values.Set("server", addr.String())
|
||||
values.Set("port", strconv.Itoa(int(port)))
|
||||
values.Set("secret", hex.EncodeToString(secret))
|
||||
values.Set("secret", secret)
|
||||
|
||||
urls.TG = makeTGURL(values)
|
||||
urls.TMe = makeTMeURL(values)
|
||||
|
||||
@@ -15,6 +15,7 @@ const (
|
||||
proxyRequestFlagsIntermediate = 0x20000000
|
||||
proxyRequestFlagsAbdridged = 0x40000000
|
||||
proxyRequestFlagsQuickAck = 0x80000000
|
||||
proxyRequestFlagsPad = 0x8000000
|
||||
)
|
||||
|
||||
var proxyRequestFlagsEncryptedPrefix [8]byte
|
||||
@@ -50,6 +51,9 @@ func (r proxyRequestFlags) String() string {
|
||||
if r&proxyRequestFlagsQuickAck != 0 {
|
||||
flags = append(flags, "QUICK_ACK")
|
||||
}
|
||||
if r&proxyRequestFlagsPad != 0 {
|
||||
flags = append(flags, "PAD")
|
||||
}
|
||||
|
||||
return strings.Join(flags, " | ")
|
||||
}
|
||||
|
||||
@@ -67,10 +67,15 @@ func (r *ProxyRequest) MakeHeader(message []byte) (*bytes.Buffer, fmt.Stringer)
|
||||
func NewProxyRequest(clientAddr, ownAddr *net.TCPAddr, opts *mtproto.ConnectionOpts, adTag []byte) (*ProxyRequest, error) {
|
||||
flags := proxyRequestFlagsHasAdTag | proxyRequestFlagsMagic | proxyRequestFlagsExtMode2
|
||||
|
||||
if opts.ConnectionType == mtproto.ConnectionTypeAbridged {
|
||||
switch opts.ConnectionType {
|
||||
case mtproto.ConnectionTypeAbridged:
|
||||
flags |= proxyRequestFlagsAbdridged
|
||||
} else {
|
||||
case mtproto.ConnectionTypeIntermediate:
|
||||
flags |= proxyRequestFlagsIntermediate
|
||||
case mtproto.ConnectionTypeSecure:
|
||||
flags |= proxyRequestFlagsIntermediate | proxyRequestFlagsPad
|
||||
default:
|
||||
panic("Unknown connection type")
|
||||
}
|
||||
|
||||
request := &ProxyRequest{
|
||||
|
||||
@@ -62,10 +62,6 @@ func (m *MTProtoIntermediate) Read() ([]byte, error) {
|
||||
return nil, errors.Annotate(err, "Cannot read the message")
|
||||
}
|
||||
|
||||
if length%4 != 0 {
|
||||
length -= length % 4
|
||||
}
|
||||
|
||||
return buf.Bytes()[:length], nil
|
||||
}
|
||||
|
||||
@@ -80,7 +76,7 @@ func (m *MTProtoIntermediate) Write(p []byte) (int, error) {
|
||||
"counter", m.writeCounter,
|
||||
)
|
||||
|
||||
if m.opts.ReadHacks.SimpleAck {
|
||||
if m.opts.WriteHacks.SimpleAck {
|
||||
return m.conn.Write(p)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package wrappers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"math/rand"
|
||||
|
||||
"github.com/9seconds/mtg/mtproto"
|
||||
)
|
||||
|
||||
// MTProtoIntermediateSecure is an extension of MTProtoIntermediate
|
||||
// mode which supports random paddings (socalled 'secure mode' or
|
||||
// 'dd-secrets').
|
||||
type MTProtoIntermediateSecure struct {
|
||||
MTProtoIntermediate
|
||||
}
|
||||
|
||||
func (m *MTProtoIntermediateSecure) Read() ([]byte, error) {
|
||||
data, err := m.MTProtoIntermediate.Read()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
length := len(data) - (len(data) % 4)
|
||||
|
||||
return data[:length], nil
|
||||
}
|
||||
|
||||
func (m *MTProtoIntermediateSecure) Write(p []byte) (int, error) {
|
||||
defer func() {
|
||||
m.writeCounter++
|
||||
}()
|
||||
|
||||
m.logger.Debugw("Write packet",
|
||||
"simple_ack", m.opts.WriteHacks.SimpleAck,
|
||||
"quick_ack", m.opts.WriteHacks.QuickAck,
|
||||
"counter", m.writeCounter,
|
||||
)
|
||||
|
||||
if m.opts.WriteHacks.SimpleAck {
|
||||
return m.conn.Write(p)
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
paddingLength := rand.Intn(4)
|
||||
buf.Grow(4 + len(p) + paddingLength)
|
||||
|
||||
binary.Write(buf, binary.LittleEndian, uint32(len(p)+paddingLength)) // nolint: errcheck
|
||||
buf.Write(p)
|
||||
buf.Write(make([]byte, paddingLength))
|
||||
|
||||
m.logger.Debugw("Write packet with padding",
|
||||
"simple_ack", m.opts.WriteHacks.SimpleAck,
|
||||
"quick_ack", m.opts.WriteHacks.QuickAck,
|
||||
"counter", m.writeCounter,
|
||||
"padding_length", paddingLength,
|
||||
"length", len(p),
|
||||
)
|
||||
|
||||
_, err := m.conn.Write(buf.Bytes())
|
||||
|
||||
return len(p), err
|
||||
}
|
||||
|
||||
// NewMTProtoIntermediateSecure create new instance of
|
||||
// MTProtoIntermediateSecure instance.
|
||||
func NewMTProtoIntermediateSecure(conn StreamReadWriteCloser, opts *mtproto.ConnectionOpts) PacketReadWriteCloser {
|
||||
return &MTProtoIntermediateSecure{
|
||||
MTProtoIntermediate: MTProtoIntermediate{
|
||||
conn: conn,
|
||||
logger: conn.Logger().Named("mtproto-intermediate-secure"),
|
||||
opts: opts,
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user