mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-09-02 00:11:56 +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)
|
connStream := conn.(wrappers.StreamReadWriteCloser)
|
||||||
|
|
||||||
newConn := wrappers.NewMTProtoAbridged(connStream, opts)
|
var newConn wrappers.PacketReadWriteCloser
|
||||||
if opts.ConnectionType != mtproto.ConnectionTypeAbridged {
|
switch opts.ConnectionType {
|
||||||
|
case mtproto.ConnectionTypeAbridged:
|
||||||
|
newConn = wrappers.NewMTProtoAbridged(connStream, opts)
|
||||||
|
case mtproto.ConnectionTypeIntermediate:
|
||||||
newConn = wrappers.NewMTProtoIntermediate(connStream, opts)
|
newConn = wrappers.NewMTProtoIntermediate(connStream, opts)
|
||||||
|
case mtproto.ConnectionTypeSecure:
|
||||||
|
newConn = wrappers.NewMTProtoIntermediateSecure(connStream, opts)
|
||||||
|
default:
|
||||||
|
panic("Unknown connection type")
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.ConnectionProto = mtproto.ConnectionProtocolIPv4
|
opts.ConnectionProto = mtproto.ConnectionProtocolIPv4
|
||||||
|
|||||||
+31
-8
@@ -18,8 +18,9 @@ const (
|
|||||||
|
|
||||||
// Config represents common configuration of mtg.
|
// Config represents common configuration of mtg.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Debug bool
|
Debug bool
|
||||||
Verbose bool
|
Verbose bool
|
||||||
|
SecureMode bool
|
||||||
|
|
||||||
BindPort uint16
|
BindPort uint16
|
||||||
PublicIPv4Port uint16
|
PublicIPv4Port uint16
|
||||||
@@ -45,8 +46,9 @@ type URLs struct {
|
|||||||
|
|
||||||
// IPURLs contains links to both ipv4 and ipv6 of the proxy.
|
// IPURLs contains links to both ipv4 and ipv6 of the proxy.
|
||||||
type IPURLs struct {
|
type IPURLs struct {
|
||||||
IPv4 URLs `json:"ipv4"`
|
IPv4 URLs `json:"ipv4"`
|
||||||
IPv6 URLs `json:"ipv6"`
|
IPv6 URLs `json:"ipv6"`
|
||||||
|
BotSecret string `json:"secret_for_mtproxybot"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindAddr returns connection for this server to bind to.
|
// BindAddr returns connection for this server to bind to.
|
||||||
@@ -65,15 +67,32 @@ func (c *Config) UseMiddleProxy() bool {
|
|||||||
return len(c.AdTag) > 0
|
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.
|
// GetURLs returns configured IPURLs instance with links to this server.
|
||||||
func (c *Config) GetURLs() IPURLs {
|
func (c *Config) GetURLs() IPURLs {
|
||||||
urls := IPURLs{}
|
urls := IPURLs{}
|
||||||
|
secret := c.SecretString()
|
||||||
if c.PublicIPv4 != nil {
|
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 {
|
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
|
return urls
|
||||||
}
|
}
|
||||||
@@ -91,8 +110,11 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo
|
|||||||
publicIPv6 net.IP, publicIPv6Port uint16,
|
publicIPv6 net.IP, publicIPv6Port uint16,
|
||||||
statsIP net.IP, statsPort uint16,
|
statsIP net.IP, statsPort uint16,
|
||||||
secret, adtag string) (*Config, error) {
|
secret, adtag string) (*Config, error) {
|
||||||
secret = strings.TrimPrefix(secret, "dd")
|
secureMode := false
|
||||||
if len(secret) != 32 {
|
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")
|
return nil, errors.New("Telegram demands secret of length 32")
|
||||||
}
|
}
|
||||||
secretBytes, err := hex.DecodeString(secret)
|
secretBytes, err := hex.DecodeString(secret)
|
||||||
@@ -149,6 +171,7 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo
|
|||||||
StatsPort: statsPort,
|
StatsPort: statsPort,
|
||||||
Secret: secretBytes,
|
Secret: secretBytes,
|
||||||
AdTag: adTagBytes,
|
AdTag: adTagBytes,
|
||||||
|
SecureMode: secureMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
return conf, nil
|
return conf, nil
|
||||||
|
|||||||
+2
-3
@@ -1,17 +1,16 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"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 := url.Values{}
|
||||||
values.Set("server", addr.String())
|
values.Set("server", addr.String())
|
||||||
values.Set("port", strconv.Itoa(int(port)))
|
values.Set("port", strconv.Itoa(int(port)))
|
||||||
values.Set("secret", hex.EncodeToString(secret))
|
values.Set("secret", secret)
|
||||||
|
|
||||||
urls.TG = makeTGURL(values)
|
urls.TG = makeTGURL(values)
|
||||||
urls.TMe = makeTMeURL(values)
|
urls.TMe = makeTMeURL(values)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const (
|
|||||||
proxyRequestFlagsIntermediate = 0x20000000
|
proxyRequestFlagsIntermediate = 0x20000000
|
||||||
proxyRequestFlagsAbdridged = 0x40000000
|
proxyRequestFlagsAbdridged = 0x40000000
|
||||||
proxyRequestFlagsQuickAck = 0x80000000
|
proxyRequestFlagsQuickAck = 0x80000000
|
||||||
|
proxyRequestFlagsPad = 0x8000000
|
||||||
)
|
)
|
||||||
|
|
||||||
var proxyRequestFlagsEncryptedPrefix [8]byte
|
var proxyRequestFlagsEncryptedPrefix [8]byte
|
||||||
@@ -50,6 +51,9 @@ func (r proxyRequestFlags) String() string {
|
|||||||
if r&proxyRequestFlagsQuickAck != 0 {
|
if r&proxyRequestFlagsQuickAck != 0 {
|
||||||
flags = append(flags, "QUICK_ACK")
|
flags = append(flags, "QUICK_ACK")
|
||||||
}
|
}
|
||||||
|
if r&proxyRequestFlagsPad != 0 {
|
||||||
|
flags = append(flags, "PAD")
|
||||||
|
}
|
||||||
|
|
||||||
return strings.Join(flags, " | ")
|
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) {
|
func NewProxyRequest(clientAddr, ownAddr *net.TCPAddr, opts *mtproto.ConnectionOpts, adTag []byte) (*ProxyRequest, error) {
|
||||||
flags := proxyRequestFlagsHasAdTag | proxyRequestFlagsMagic | proxyRequestFlagsExtMode2
|
flags := proxyRequestFlagsHasAdTag | proxyRequestFlagsMagic | proxyRequestFlagsExtMode2
|
||||||
|
|
||||||
if opts.ConnectionType == mtproto.ConnectionTypeAbridged {
|
switch opts.ConnectionType {
|
||||||
|
case mtproto.ConnectionTypeAbridged:
|
||||||
flags |= proxyRequestFlagsAbdridged
|
flags |= proxyRequestFlagsAbdridged
|
||||||
} else {
|
case mtproto.ConnectionTypeIntermediate:
|
||||||
flags |= proxyRequestFlagsIntermediate
|
flags |= proxyRequestFlagsIntermediate
|
||||||
|
case mtproto.ConnectionTypeSecure:
|
||||||
|
flags |= proxyRequestFlagsIntermediate | proxyRequestFlagsPad
|
||||||
|
default:
|
||||||
|
panic("Unknown connection type")
|
||||||
}
|
}
|
||||||
|
|
||||||
request := &ProxyRequest{
|
request := &ProxyRequest{
|
||||||
|
|||||||
@@ -62,10 +62,6 @@ func (m *MTProtoIntermediate) Read() ([]byte, error) {
|
|||||||
return nil, errors.Annotate(err, "Cannot read the message")
|
return nil, errors.Annotate(err, "Cannot read the message")
|
||||||
}
|
}
|
||||||
|
|
||||||
if length%4 != 0 {
|
|
||||||
length -= length % 4
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.Bytes()[:length], nil
|
return buf.Bytes()[:length], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +76,7 @@ func (m *MTProtoIntermediate) Write(p []byte) (int, error) {
|
|||||||
"counter", m.writeCounter,
|
"counter", m.writeCounter,
|
||||||
)
|
)
|
||||||
|
|
||||||
if m.opts.ReadHacks.SimpleAck {
|
if m.opts.WriteHacks.SimpleAck {
|
||||||
return m.conn.Write(p)
|
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