diff --git a/mtglib/internal/faketls/clienthello/clienthello.go b/mtglib/internal/faketls/clienthello.go similarity index 73% rename from mtglib/internal/faketls/clienthello/clienthello.go rename to mtglib/internal/faketls/clienthello.go index 4789029..3ee9aa0 100644 --- a/mtglib/internal/faketls/clienthello/clienthello.go +++ b/mtglib/internal/faketls/clienthello.go @@ -1,4 +1,4 @@ -package clienthello +package faketls import ( "crypto/hmac" @@ -16,10 +16,10 @@ type ClientHello struct { SessionID []byte } -func ParseHandshake(secret, handshake []byte) (ClientHello, error) { +func ParseClientHello(secret, handshake []byte) (ClientHello, error) { hello := ClientHello{} - if len(handshake) < MinLen { + if len(handshake) < ClientHelloMinLen { return hello, fmt.Errorf("lengh of handshake is too small: %d", len(handshake)) } @@ -27,9 +27,9 @@ func ParseHandshake(secret, handshake []byte) (ClientHello, error) { return hello, fmt.Errorf("unknown handshake type %#x", handshake[0]) } - copy(hello.Digest[:], handshake[RandomOffset:]) + copy(hello.Digest[:], handshake[ClientHelloRandomOffset:]) - for i := RandomOffset; i < RandomOffset+RandomLen; i++ { + for i := ClientHelloRandomOffset; i < ClientHelloRandomOffset+RandomLen; i++ { handshake[i] = 0 } @@ -60,8 +60,8 @@ func ParseHandshake(secret, handshake []byte) (ClientHello, error) { timestamp := int64(binary.LittleEndian.Uint32(computedDigest[RandomLen-4:])) hello.Time = time.Unix(timestamp, 0) - hello.SessionID = make([]byte, handshake[SessionIDOffset]) - copy(hello.SessionID, handshake[SessionIDOffset+1:]) + hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset]) + copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:]) return hello, nil } diff --git a/mtglib/internal/faketls/clienthello/init.go b/mtglib/internal/faketls/clienthello/init.go deleted file mode 100644 index c597b84..0000000 --- a/mtglib/internal/faketls/clienthello/init.go +++ /dev/null @@ -1,17 +0,0 @@ -package clienthello - -import "errors" - -const ( - RandomLen = 32 - RandomOffset = 6 - SessionIDOffset = RandomOffset + RandomLen - MinLen = SessionIDOffset + 1 - - HandshakeTypeClient = 0x01 -) - -var ( - ErrBadDigest = errors.New("bad digest") - ErrAntiReplayAttack = errors.New("antireplay attack was detected") -) diff --git a/mtglib/internal/faketls/init.go b/mtglib/internal/faketls/init.go new file mode 100644 index 0000000..081a9ba --- /dev/null +++ b/mtglib/internal/faketls/init.go @@ -0,0 +1,18 @@ +package faketls + +import "errors" + +const ( + RandomLen = 32 + + ClientHelloRandomOffset = 6 + ClientHelloSessionIDOffset = ClientHelloRandomOffset + RandomLen + ClientHelloMinLen = ClientHelloSessionIDOffset + 1 + + HandshakeTypeClient = 0x01 +) + +var ( + ErrBadDigest = errors.New("bad digest") + ErrAntiReplayAttack = errors.New("antireplay attack was detected") +) diff --git a/mtglib/proxy.go b/mtglib/proxy.go index 7273375..8ce024d 100644 --- a/mtglib/proxy.go +++ b/mtglib/proxy.go @@ -8,7 +8,7 @@ import ( "sync" "time" - "github.com/9seconds/mtg/v2/mtglib/internal/faketls/clienthello" + "github.com/9seconds/mtg/v2/mtglib/internal/faketls" "github.com/9seconds/mtg/v2/mtglib/internal/faketls/record" "github.com/9seconds/mtg/v2/mtglib/internal/obfuscated2" "github.com/9seconds/mtg/v2/mtglib/internal/relay" @@ -58,7 +58,7 @@ func (p *Proxy) ServeConn(conn net.Conn) { ctx.logger.Info("Stream has been finished") }() - if err := p.doFakeTLSHandshake(ctx); err != nil { + if err := p.doFakeTLSHandshake(ctx, ctx.clientConn); err != nil { p.logger.InfoError("faketls handshake is failed", err) return @@ -121,17 +121,28 @@ func (p *Proxy) Shutdown() { p.workerPool.Release() } -func (p *Proxy) doFakeTLSHandshake(ctx *streamContext) error { +func (p *Proxy) doFakeTLSHandshake(ctx *streamContext, conn net.Conn) error { clientHelloRecord := record.AcquireRecord() defer record.ReleaseRecord(clientHelloRecord) - if err := clientHelloRecord.Read(ctx.clientConn); err != nil { + if err := clientHelloRecord.Read(conn); err != nil { return fmt.Errorf("cannot read client hello: %w", err) } - hello, _ := clienthello.ParseHandshake(p.secret.Key[:], + hello, err := faketls.ParseClientHello(p.secret.Key[:], clientHelloRecord.Payload.Bytes()) - fmt.Println(hello) + if err != nil { + return fmt.Errorf("cannot parse client hello: %w", err) + } + + if err := p.timeAttackDetector.Valid(hello.Time); err != nil { + return fmt.Errorf("invalid time: %w", err) + } + if p.antiReplayCache.SeenBefore(hello.SessionID) { + p.logger.Warning("anti replay attack was detected") + + return fmt.Errorf("anti replay attack from %s", ctx.ClientIP().String()) + } return fmt.Errorf("SUCCESS") }