mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 15:54:03 +03:00
Success path for fake tls is implemented
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package faketls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/ring"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/9seconds/mtg/config"
|
||||
)
|
||||
|
||||
type connectionServer struct {
|
||||
nextWriteItem *ring.Ring
|
||||
nextReadItem *ring.Ring
|
||||
|
||||
ctx context.Context
|
||||
channelGet chan chan<- []byte
|
||||
}
|
||||
|
||||
func (c *connectionServer) get() ([]byte, error) {
|
||||
resp := make(chan []byte)
|
||||
select {
|
||||
case <-c.ctx.Done():
|
||||
return nil, errors.New("context closed")
|
||||
case c.channelGet <- resp:
|
||||
return <-resp, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *connectionServer) fetch() ([]byte, error) {
|
||||
addr := net.JoinHostPort(config.C.CloakHost, strconv.Itoa(config.C.CloakPort))
|
||||
conn, err := tls.Dial("tcp", addr, &tls.Config{InsecureSkipVerify: true}) // nolint: gosec
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot connect to the masked host: %w", err)
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
if err = conn.Handshake(); err != nil {
|
||||
return nil, fmt.Errorf("cannot perform tls handshake: %w", err)
|
||||
}
|
||||
|
||||
certificates := conn.ConnectionState().PeerCertificates
|
||||
if len(certificates) == 0 {
|
||||
return nil, errors.New("no certificates is found")
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
for _, v := range certificates {
|
||||
buf.Write(v.Raw)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (c *connectionServer) run(tickEvery time.Duration) {
|
||||
logger := zap.S().Named("tls-connection-server")
|
||||
|
||||
ticker := time.NewTicker(tickEvery)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-c.ctx.Done():
|
||||
return
|
||||
case resp := <-c.channelGet:
|
||||
resp <- c.nextReadItem.Value.([]byte)
|
||||
close(resp)
|
||||
|
||||
c.nextReadItem = c.nextReadItem.Next()
|
||||
case <-ticker.C:
|
||||
cert, err := c.fetch()
|
||||
switch err {
|
||||
case nil:
|
||||
c.nextWriteItem.Value = cert
|
||||
c.nextWriteItem = c.nextWriteItem.Next()
|
||||
default:
|
||||
logger.Warnw("cannot fetch certificates", "error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,18 @@ package faketls
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/antireplay"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/obfuscated2"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
"github.com/9seconds/mtg/stats"
|
||||
"github.com/9seconds/mtg/tlstypes"
|
||||
"github.com/9seconds/mtg/wrappers/stream"
|
||||
)
|
||||
|
||||
@@ -18,18 +27,77 @@ func (c *ClientProtocol) Handshake(socket conntypes.StreamReadWriteCloser) (conn
|
||||
|
||||
for _, expected := range faketlsStartBytes {
|
||||
if actual, err := bufferedReader.ReadByte(); err != nil || actual != expected {
|
||||
return nil, c.simulateWebsite(rewinded)
|
||||
fmt.Println("!!!!!!!!!!!! ERROR !!!!!!!!!!!!", err)
|
||||
return nil, errors.New("qqq")
|
||||
}
|
||||
}
|
||||
|
||||
rewinded.Rewind()
|
||||
rewinded = stream.NewRewind(rewinded)
|
||||
|
||||
if err := c.tlsHandshake(rewinded); err != nil {
|
||||
return nil, c.simulateWebsite(rewinded)
|
||||
fmt.Println("!!!!!!!!!!!! ERROR !!!!!!!!!!!!", err)
|
||||
return nil, errors.New("qqq")
|
||||
}
|
||||
|
||||
conn, err := c.ClientProtocol.Handshake(socket)
|
||||
conn := stream.NewFakeTLS(socket)
|
||||
conn, err := c.ClientProtocol.Handshake(conn)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, err
|
||||
}
|
||||
|
||||
func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
|
||||
helloRecord, err := tlstypes.ReadRecord(conn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read initial record: %w", err)
|
||||
}
|
||||
|
||||
clientHello, err := tlstypes.ParseClientHello(helloRecord.Data.Bytes())
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse client hello: %w", err)
|
||||
}
|
||||
|
||||
digest := clientHello.Digest()
|
||||
for i := 0; i < len(digest)-4; i++ {
|
||||
if digest[i] != 0 {
|
||||
return errBadDigest
|
||||
}
|
||||
}
|
||||
|
||||
timestamp := int64(binary.LittleEndian.Uint32(digest[len(digest)-4:]))
|
||||
createdAt := time.Unix(timestamp, 0)
|
||||
timeDiff := time.Since(createdAt)
|
||||
|
||||
if (timeDiff > TimeSkew || timeDiff < -TimeSkew) && timestamp > TimeFromBoot {
|
||||
return errBadTime
|
||||
}
|
||||
|
||||
if antireplay.Cache.HasTLS(clientHello.Random[:]) {
|
||||
stats.Stats.AntiReplayDetected()
|
||||
return errors.New("antireplay detected")
|
||||
}
|
||||
|
||||
antireplay.Cache.AddTLS(clientHello.Random[:])
|
||||
|
||||
hostCert, err := connectionServerInstance.get()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot get host certificate: %w", err)
|
||||
}
|
||||
|
||||
serverHello := tlstypes.NewServerHello(clientHello)
|
||||
serverHelloPacket := serverHello.WelcomePacket(hostCert)
|
||||
|
||||
if _, err := conn.Write(serverHelloPacket); err != nil {
|
||||
return fmt.Errorf("cannot send welcome packet: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func MakeClientProtocol() protocol.ClientProtocol {
|
||||
return &ClientProtocol{}
|
||||
}
|
||||
|
||||
+23
-14
@@ -1,21 +1,30 @@
|
||||
package faketls
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
TLSHandshakeLength = 1 + 2 + 2 + 512
|
||||
TimeSkew = 5 * time.Second
|
||||
TimeFromBoot = 24 * 60 * 60
|
||||
)
|
||||
|
||||
var (
|
||||
faketlsStartBytes = [...]byte{
|
||||
0x16,
|
||||
0x03,
|
||||
0x01,
|
||||
0x02,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
0x01,
|
||||
0xfc,
|
||||
0x03,
|
||||
0x03,
|
||||
}
|
||||
errBadDigest = errors.New("bad digest")
|
||||
errBadTime = errors.New("bad time")
|
||||
|
||||
faketlsStartBytes = [...]byte{
|
||||
0x16,
|
||||
0x03,
|
||||
0x01,
|
||||
0x02,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
0x01,
|
||||
0xfc,
|
||||
0x03,
|
||||
0x03,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package faketls
|
||||
|
||||
import (
|
||||
"container/ring"
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/config"
|
||||
)
|
||||
|
||||
var (
|
||||
connectionServerInstance connectionServer
|
||||
connectionServerInitOnce sync.Once
|
||||
)
|
||||
|
||||
const (
|
||||
connectionServerKeepCertificates = 5
|
||||
connectionServerUpdateEvery = 10 * time.Minute
|
||||
)
|
||||
|
||||
func Init(ctx context.Context) {
|
||||
connectionServerInitOnce.Do(func() {
|
||||
if config.C.CloakHost == "" {
|
||||
return
|
||||
}
|
||||
|
||||
connectionServerInstance = connectionServer{
|
||||
channelGet: make(chan chan<- []byte),
|
||||
ctx: ctx,
|
||||
}
|
||||
|
||||
cert, err := connectionServerInstance.fetch()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
r := ring.New(connectionServerKeepCertificates)
|
||||
|
||||
for i := 0; i < connectionServerKeepCertificates; i++ {
|
||||
r.Value = cert
|
||||
r = r.Next()
|
||||
}
|
||||
|
||||
connectionServerInstance.nextWriteItem = r
|
||||
connectionServerInstance.nextReadItem = r
|
||||
|
||||
go connectionServerInstance.run(connectionServerUpdateEvery)
|
||||
})
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package faketls
|
||||
|
||||
import (
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
)
|
||||
|
||||
func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.StreamReadWriteCloser, error) {
|
||||
return nil, nil
|
||||
}
|
||||
Reference in New Issue
Block a user