diff --git a/mtglib/internal/doppel/ganger.go b/mtglib/internal/doppel/ganger.go index 835ab12..4d6b355 100644 --- a/mtglib/internal/doppel/ganger.go +++ b/mtglib/internal/doppel/ganger.go @@ -9,13 +9,13 @@ import ( ) const ( - DoppelGangerMaxDurations = 4096 + DoppelGangerMaxDurations = 4096 DoppelGangerScoutRaidEach = 30 * time.Minute - DoppelGangerScoutRepeats = 10 + DoppelGangerScoutRepeats = 10 ) type gangerConnRequest struct { - ret chan Conn + ret chan<- Conn payload essentials.Conn } @@ -25,7 +25,7 @@ type Ganger struct { logger Logger wg sync.WaitGroup - scout Scout + scout Scout scoutRaidEach time.Duration scoutRaidRepeats int @@ -47,8 +47,9 @@ func (g *Ganger) Run() { } func (g *Ganger) NewConn(conn essentials.Conn) (Conn, error) { + rvChan := make(chan Conn) req := gangerConnRequest{ - ret: make(chan Conn), + ret: rvChan, payload: conn, } defer close(req.ret) @@ -62,7 +63,7 @@ func (g *Ganger) NewConn(conn essentials.Conn) (Conn, error) { select { case <-g.ctx.Done(): return Conn{}, context.Cause(g.ctx) - case conn := <-req.ret: + case conn := <-rvChan: return conn, nil } } @@ -158,9 +159,9 @@ func NewGanger( } return &Ganger{ - ctx: ctx, - ctxCancel: cancel, - logger: logger, + ctx: ctx, + ctxCancel: cancel, + logger: logger, scoutRaidEach: scoutEach, scoutRaidRepeats: scoutRepeats, stats: &Stats{ diff --git a/mtglib/proxy.go b/mtglib/proxy.go index 9ac8412..40a2bbf 100644 --- a/mtglib/proxy.go +++ b/mtglib/proxy.go @@ -78,19 +78,32 @@ func (p *Proxy) ServeConn(conn essentials.Conn) { ctx.logger.Info("Stream has been finished") }() - if !p.doFakeTLSHandshake(ctx) { + noise, ok := p.doFakeTLSHandshake(ctx) + if !ok { return } - if err := p.doObfuscatedHandshake(ctx); err != nil { - p.logger.InfoError("obfuscated handshake is failed", err) + clientConn, err := p.doppelGanger.NewConn(ctx.clientConn) + if err != nil { + ctx.logger.InfoError("cannot wrap into doppelganger connection", err) + return + } + defer clientConn.Stop() + if _, err := clientConn.Write(noise); err != nil { + ctx.logger.InfoError("cannot send the first packet", err) + return + } + + ctx.clientConn = clientConn + + if err := p.doObfuscatedHandshake(ctx); err != nil { + ctx.logger.InfoError("obfuscated handshake is failed", err) return } if err := p.doTelegramCall(ctx); err != nil { - p.logger.WarningError("cannot dial to telegram", err) - + ctx.logger.WarningError("cannot dial to telegram", err) return } @@ -163,7 +176,7 @@ func (p *Proxy) Shutdown() { p.blocklist.Shutdown() } -func (p *Proxy) doFakeTLSHandshake(ctx *streamContext) bool { +func (p *Proxy) doFakeTLSHandshake(ctx *streamContext) ([]byte, bool) { rewind := newConnRewind(ctx.clientConn) clientHello, err := fake.ReadClientHello( @@ -175,31 +188,25 @@ func (p *Proxy) doFakeTLSHandshake(ctx *streamContext) bool { if err != nil { p.logger.InfoError("cannot read client hello", err) p.doDomainFronting(ctx, rewind) - return false + return nil, false } if p.antiReplayCache.SeenBefore(clientHello.SessionID) { p.logger.Warning("replay attack has been detected!") p.eventStream.Send(p.ctx, NewEventReplayAttack(ctx.streamID)) p.doDomainFronting(ctx, rewind) - return false + return nil, false } - _, err = fake.SendServerHello(ctx.clientConn, p.secret.Key[:], clientHello) + noise, err := fake.SendServerHello(ctx.clientConn, p.secret.Key[:], clientHello) if err != nil { p.logger.InfoError("cannot send welcome packet", err) - return false + return nil, false } ctx.clientConn = tls.New(ctx.clientConn, true, true) - ctx.clientConn, err = p.doppelGanger.NewConn(ctx.clientConn) - if err != nil { - p.logger.WarningError("cannot create connection", err) - return false - } - - return true + return noise, true } func (p *Proxy) doObfuscatedHandshake(ctx *streamContext) error {