diff --git a/client/direct.go b/client/direct.go index 8ef2dc7..1e38e5e 100644 --- a/client/direct.go +++ b/client/direct.go @@ -32,9 +32,8 @@ func DirectInit(conn net.Conn, conf *config.Config) (*mtproto.ConnectionOpts, wr return nil, nil, errors.Annotate(err, "Cannot parse obfuscated frame") } connOpts.ConnectionProto = mtproto.ConnectionProtocolAny - connOpts.ClientAddr = conn.RemoteAddr().(*net.TCPAddr) - socket := wrappers.NewTimeoutRWC(conn) + socket := wrappers.NewTimeoutRWC(conn, conf.PublicIPv4, conf.PublicIPv6) socket = wrappers.NewStreamCipherRWC(socket, obfs2.Encryptor, obfs2.Decryptor) return connOpts, socket, nil diff --git a/config/config.go b/config/config.go index 9935fa8..d988c38 100644 --- a/config/config.go +++ b/config/config.go @@ -59,16 +59,6 @@ func (c *Config) BindAddr() string { return getAddr(c.BindIP, c.BindPort) } -// IPv4Addr returns connection string to ipv6 for mtproto proxy. -func (c *Config) IPv4Addr() string { - return getAddr(c.PublicIPv4, c.PublicIPv4Port) -} - -// IPv6Addr returns connection string to ipv6 for mtproto proxy. -func (c *Config) IPv6Addr() string { - return getAddr(c.PublicIPv6, c.PublicIPv6Port) -} - // StatAddr returns connection string to the stats API. func (c *Config) StatAddr() string { return getAddr(c.StatsIP, c.StatsPort) @@ -76,10 +66,15 @@ func (c *Config) StatAddr() string { // GetURLs returns configured IPURLs instance with links to this server. func (c *Config) GetURLs() IPURLs { - return IPURLs{ - IPv4: getURLs(c.PublicIPv4, c.PublicIPv4Port, c.Secret), - IPv6: getURLs(c.PublicIPv6, c.PublicIPv6Port, c.Secret), + urls := IPURLs{} + if c.PublicIPv4 != nil { + urls.IPv4 = getURLs(c.PublicIPv4, c.PublicIPv4Port, c.Secret) } + if c.PublicIPv6 != nil { + urls.IPv6 = getURLs(c.PublicIPv6, c.PublicIPv6Port, c.Secret) + } + + return urls } func getAddr(host fmt.Stringer, port uint16) string { @@ -106,12 +101,11 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo if publicIPv4 == nil { publicIPv4, err = getGlobalIPv4() if err != nil { - return nil, errors.Errorf("Cannot get public IP") + publicIPv4 = nil + } else if publicIPv4.To4() == nil { + return nil, errors.Errorf("IP %s is not IPv4", publicIPv4.String()) } } - if publicIPv4.To4() == nil { - return nil, errors.Errorf("IP %s is not IPv4", publicIPv4.String()) - } if PublicIPv4Port == 0 { PublicIPv4Port = bindPort } @@ -119,12 +113,11 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo if publicIPv6 == nil { publicIPv6, err = getGlobalIPv6() if err != nil { - publicIPv6 = publicIPv4 + publicIPv6 = nil + } else if publicIPv6.To4() != nil { + return nil, errors.Errorf("IP %s is not IPv6", publicIPv6.String()) } } - if publicIPv6.To16() == nil { - return nil, errors.Errorf("IP %s is not IPv6", publicIPv6.String()) - } if publicIPv6Port == 0 { publicIPv6Port = bindPort } diff --git a/main.go b/main.go index fa63cfc..8154f6f 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ package main import ( "encoding/json" + "fmt" "io" "math/rand" "os" @@ -15,7 +16,8 @@ import ( kingpin "gopkg.in/alecthomas/kingpin.v2" "github.com/9seconds/mtg/config" - "github.com/9seconds/mtg/proxy" + "github.com/9seconds/mtg/mtproto" + "github.com/9seconds/mtg/telegram" "github.com/juju/errors" ) @@ -112,15 +114,29 @@ func main() { atom, )).Sugar() - stat := proxy.NewStats(conf) - go stat.Serve() - - srv := proxy.NewServer(conf, logger, stat) - printURLs(conf.GetURLs()) - - if err := srv.Serve(); err != nil { - logger.Fatal(err.Error()) + tg := telegram.NewMiddleTelegram(conf, logger) + connOpts := &mtproto.ConnectionOpts{ + DC: int16(1), + ConnectionType: mtproto.ConnectionTypeAbridged, + ConnectionProto: mtproto.ConnectionProtocolIPv4, } + + sock, err := tg.Dial(connOpts) + if err != nil { + panic(err) + } + _, err = tg.Init(connOpts, sock) + fmt.Println(err) + + // stat := proxy.NewStats(conf) + // go stat.Serve() + + // srv := proxy.NewServer(conf, logger, stat) + // printURLs(conf.GetURLs()) + + // if err := srv.Serve(); err != nil { + // logger.Fatal(err.Error()) + // } } func setRLimit() (err error) { diff --git a/mtproto/connection_options.go b/mtproto/connection_options.go index 0f82ec0..823b81b 100644 --- a/mtproto/connection_options.go +++ b/mtproto/connection_options.go @@ -2,7 +2,6 @@ package mtproto import ( "bytes" - "net" "github.com/juju/errors" ) @@ -19,7 +18,8 @@ type ConnectionOpts struct { DC int16 ConnectionType ConnectionType ConnectionProto ConnectionProtocol - ClientAddr *net.TCPAddr + QuickAck bool + SimpleAck bool } // Different connection types which user requests from Telegram. diff --git a/mtproto/rpc/rpc_handshake_request.go b/mtproto/rpc/rpc_handshake_request.go index c0a30a6..0625c67 100644 --- a/mtproto/rpc/rpc_handshake_request.go +++ b/mtproto/rpc/rpc_handshake_request.go @@ -1,6 +1,8 @@ package rpc -import "bytes" +import ( + "bytes" +) const ( rpcHandshakeTagLength = 4 diff --git a/mtproto/wrappers/crypt.go b/mtproto/wrappers/crypt.go index b790348..fc9bf63 100644 --- a/mtproto/wrappers/crypt.go +++ b/mtproto/wrappers/crypt.go @@ -22,11 +22,12 @@ const ( var emptyIP = [4]byte{0x00, 0x00, 0x00, 0x00} -func NewMiddleProxyCipherRWC(conn wrappers.ReadWriteCloserWithAddr, req *rpc.RPCNonceRequest, - resp *rpc.RPCNonceResponse, client *net.TCPAddr, secret []byte) wrappers.ReadWriteCloserWithAddr { - remote := conn.Addr() - encKey, encIV := makeKeys(CipherPurposeClient, req, resp, client, remote, secret) - decKey, decIV := makeKeys(CipherPurposeServer, req, resp, client, remote, secret) +func NewMiddleProxyCipherRWC(conn wrappers.ReadWriteCloserWithAddr, req *rpc.RPCNonceRequest, resp *rpc.RPCNonceResponse, secret []byte) wrappers.ReadWriteCloserWithAddr { + localAddr := conn.LocalAddr() + remoteAddr := conn.RemoteAddr() + + encKey, encIV := makeKeys(CipherPurposeClient, req, resp, localAddr, remoteAddr, secret) + decKey, decIV := makeKeys(CipherPurposeServer, req, resp, localAddr, remoteAddr, secret) enc, _ := makeEncrypterDecrypter(encKey, encIV) _, dec := makeEncrypterDecrypter(decKey, decIV) diff --git a/mtproto/wrappers/frame.go b/mtproto/wrappers/frame.go index 784762f..d008d37 100644 --- a/mtproto/wrappers/frame.go +++ b/mtproto/wrappers/frame.go @@ -112,8 +112,12 @@ func (f *FrameRWC) Close() error { return f.conn.Close() } -func (f *FrameRWC) Addr() *net.TCPAddr { - return f.conn.Addr() +func (f *FrameRWC) LocalAddr() *net.TCPAddr { + return f.conn.LocalAddr() +} + +func (f *FrameRWC) RemoteAddr() *net.TCPAddr { + return f.conn.RemoteAddr() } func NewFrameRWC(conn wrappers.ReadWriteCloserWithAddr, seqNo int32) wrappers.ReadWriteCloserWithAddr { diff --git a/telegram/dialer.go b/telegram/dialer.go index f0d9cb5..9cf048b 100644 --- a/telegram/dialer.go +++ b/telegram/dialer.go @@ -14,6 +14,8 @@ const telegramDialTimeout = 10 * time.Second type tgDialer struct { net.Dialer + + conf *config.Config } func (t *tgDialer) dial(addr string) (net.Conn, error) { @@ -34,5 +36,5 @@ func (t *tgDialer) dialRWC(addr string) (wrappers.ReadWriteCloserWithAddr, error return nil, err } - return wrappers.NewTimeoutRWC(conn), nil + return wrappers.NewTimeoutRWC(conn, t.conf.PublicIPv4, t.conf.PublicIPv6), nil } diff --git a/telegram/direct.go b/telegram/direct.go index 81fb2eb..8975f71 100644 --- a/telegram/direct.go +++ b/telegram/direct.go @@ -57,7 +57,10 @@ func (t *directTelegram) Init(connOpts *mtproto.ConnectionOpts, conn wrappers.Re // to Telegram bypassing middleproxies. func NewDirectTelegram(conf *config.Config) Telegram { return &directTelegram{baseTelegram{ - dialer: tgDialer{net.Dialer{Timeout: telegramDialTimeout}}, + dialer: tgDialer{ + Dialer: net.Dialer{Timeout: telegramDialTimeout}, + conf: conf, + }, v4Addresses: directV4Addresses, v6Addresses: directV6Addresses, }} diff --git a/telegram/middle.go b/telegram/middle.go index b3b4ed3..03d70cd 100644 --- a/telegram/middle.go +++ b/telegram/middle.go @@ -1,6 +1,7 @@ package telegram import ( + "fmt" "io" "net" "net/http" @@ -24,7 +25,10 @@ func NewMiddleTelegram(conf *config.Config, logger *zap.SugaredLogger) Telegram tg := &middleTelegram{ middleTelegramCaller: middleTelegramCaller{ baseTelegram: baseTelegram{ - dialer: tgDialer{net.Dialer{Timeout: telegramDialTimeout}}, + dialer: tgDialer{ + Dialer: net.Dialer{Timeout: telegramDialTimeout}, + conf: conf, + }, }, logger: logger, httpClient: &http.Client{ @@ -54,8 +58,7 @@ func (t *middleTelegram) Init(connOpts *mtproto.ConnectionOpts, conn wrappers.Re return nil, err } - secureConn := mtwrappers.NewMiddleProxyCipherRWC(conn, rpcNonceReq, - rpcNonceResp, connOpts.ClientAddr, t.proxySecret) + secureConn := mtwrappers.NewMiddleProxyCipherRWC(conn, rpcNonceReq, rpcNonceResp, t.proxySecret) secureConn = mtwrappers.NewFrameRWC(secureConn, rpc.RPCHandshakeSeqNo) rpcHandshakeReq, err := t.sendRPCHandshakeRequest(secureConn) @@ -123,6 +126,7 @@ func (t *middleTelegram) receiveRPCHandshakeResponse(conn io.Reader, req *rpc.RP if err = rpcHandshakeResp.Valid(req); err != nil { return nil, errors.Annotate(err, "Invalid RPC handshake response") } + fmt.Println("VICTORY") return rpcHandshakeResp, nil } diff --git a/wrappers/blockcipherrwc.go b/wrappers/blockcipherrwc.go index 4d11d5d..9db024d 100644 --- a/wrappers/blockcipherrwc.go +++ b/wrappers/blockcipherrwc.go @@ -25,6 +25,7 @@ func (c *BlockCipherReadWriteCloserWithAddr) Read(p []byte) (int, error) { return errors.Annotate(err, "Cannot read from socket") } c.Buffer.Write(p[:n]) + bufferLength = c.Buffer.Len() } c.decryptor.CryptBlocks(c.Buffer.Bytes(), c.Buffer.Bytes()) @@ -47,8 +48,12 @@ func (c *BlockCipherReadWriteCloserWithAddr) Close() error { return c.conn.Close() } -func (c *BlockCipherReadWriteCloserWithAddr) Addr() *net.TCPAddr { - return c.conn.Addr() +func (c *BlockCipherReadWriteCloserWithAddr) LocalAddr() *net.TCPAddr { + return c.conn.LocalAddr() +} + +func (c *BlockCipherReadWriteCloserWithAddr) RemoteAddr() *net.TCPAddr { + return c.conn.RemoteAddr() } func NewBlockCipherRWC(conn ReadWriteCloserWithAddr, encryptor, decryptor cipher.BlockMode) ReadWriteCloserWithAddr { diff --git a/wrappers/ctxrwc.go b/wrappers/ctxrwc.go index b378a96..64c1006 100644 --- a/wrappers/ctxrwc.go +++ b/wrappers/ctxrwc.go @@ -48,8 +48,12 @@ func (c *CtxReadWriteCloserWithAddr) Close() error { return c.conn.Close() } -func (c *CtxReadWriteCloserWithAddr) Addr() *net.TCPAddr { - return c.conn.Addr() +func (c *CtxReadWriteCloserWithAddr) LocalAddr() *net.TCPAddr { + return c.conn.LocalAddr() +} + +func (c *CtxReadWriteCloserWithAddr) RemoteAddr() *net.TCPAddr { + return c.conn.RemoteAddr() } // NewCtxRWC returns ReadWriteCloser which respects given context, diff --git a/wrappers/logrwc.go b/wrappers/logrwc.go index bab7af7..fd80ad4 100644 --- a/wrappers/logrwc.go +++ b/wrappers/logrwc.go @@ -36,8 +36,12 @@ func (l *LogReadWriteCloserWithAddr) Close() error { return err } -func (l *LogReadWriteCloserWithAddr) Addr() *net.TCPAddr { - return l.conn.Addr() +func (l *LogReadWriteCloserWithAddr) LocalAddr() *net.TCPAddr { + return l.conn.LocalAddr() +} + +func (l *LogReadWriteCloserWithAddr) RemoteAddr() *net.TCPAddr { + return l.conn.RemoteAddr() } // NewLogRWC wraps ReadWriteCloser with logger calls. diff --git a/wrappers/rwcaddr.go b/wrappers/rwcaddr.go index 804bc5a..6ca4299 100644 --- a/wrappers/rwcaddr.go +++ b/wrappers/rwcaddr.go @@ -8,5 +8,6 @@ import ( type ReadWriteCloserWithAddr interface { io.ReadWriteCloser - Addr() *net.TCPAddr + LocalAddr() *net.TCPAddr + RemoteAddr() *net.TCPAddr } diff --git a/wrappers/streamcipherrwc.go b/wrappers/streamcipherrwc.go index d847c72..a5f15d1 100644 --- a/wrappers/streamcipherrwc.go +++ b/wrappers/streamcipherrwc.go @@ -43,8 +43,12 @@ func (c *StreamCipherReadWriteCloserWithAddr) Close() error { return c.conn.Close() } -func (c *StreamCipherReadWriteCloserWithAddr) Addr() *net.TCPAddr { - return c.conn.Addr() +func (c *StreamCipherReadWriteCloserWithAddr) LocalAddr() *net.TCPAddr { + return c.conn.LocalAddr() +} + +func (c *StreamCipherReadWriteCloserWithAddr) RemoteAddr() *net.TCPAddr { + return c.conn.RemoteAddr() } // NewStreamCipherRWC returns wrapper which transparently diff --git a/wrappers/timeoutrwc.go b/wrappers/timeoutrwc.go index e758600..952ade1 100644 --- a/wrappers/timeoutrwc.go +++ b/wrappers/timeoutrwc.go @@ -8,7 +8,9 @@ import ( ) type TimeoutReadWriteCloserWithAddr struct { - conn net.Conn + conn net.Conn + publicIPv4 net.IP + publicIPv6 net.IP } func (t *TimeoutReadWriteCloserWithAddr) Read(p []byte) (int, error) { @@ -25,10 +27,29 @@ func (t *TimeoutReadWriteCloserWithAddr) Close() error { return t.conn.Close() } -func (t *TimeoutReadWriteCloserWithAddr) Addr() *net.TCPAddr { +func (t *TimeoutReadWriteCloserWithAddr) RemoteAddr() *net.TCPAddr { return t.conn.RemoteAddr().(*net.TCPAddr) } -func NewTimeoutRWC(conn net.Conn) ReadWriteCloserWithAddr { - return &TimeoutReadWriteCloserWithAddr{conn} +func (t *TimeoutReadWriteCloserWithAddr) LocalAddr() *net.TCPAddr { + addr := t.conn.LocalAddr().(*net.TCPAddr) + newAddr := *addr + + if t.RemoteAddr().IP.To4() != nil { + if t.publicIPv4 != nil { + newAddr.IP = t.publicIPv4 + } + } else if t.publicIPv6 != nil { + newAddr.IP = t.publicIPv6 + } + + return &newAddr +} + +func NewTimeoutRWC(conn net.Conn, ipv4, ipv6 net.IP) ReadWriteCloserWithAddr { + return &TimeoutReadWriteCloserWithAddr{ + conn: conn, + publicIPv4: ipv4, + publicIPv6: ipv6, + } } diff --git a/wrappers/trafficrwc.go b/wrappers/trafficrwc.go index 78518ad..60dd8c2 100644 --- a/wrappers/trafficrwc.go +++ b/wrappers/trafficrwc.go @@ -29,8 +29,12 @@ func (t *TrafficReadWriteCloserWithAddr) Close() error { return t.conn.Close() } -func (t *TrafficReadWriteCloserWithAddr) Addr() *net.TCPAddr { - return t.conn.Addr() +func (t *TrafficReadWriteCloserWithAddr) LocalAddr() *net.TCPAddr { + return t.conn.LocalAddr() +} + +func (t *TrafficReadWriteCloserWithAddr) RemoteAddr() *net.TCPAddr { + return t.conn.RemoteAddr() } // NewTrafficRWC wraps ReadWriteCloser to have read/write callbacks.