From 1a6129b66ff3e66c347b54fbae203c1c61d12d74 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 20 Jun 2019 22:40:55 +0000 Subject: [PATCH] obfs4: Alter tear down behavior to be less distinctive The old behavior closed the connection on handshake failure after: * The first N bytes (random on a per-server basis). * The first M seconds (random on a per-server basis). Whichever came first. As Sergey Frolov kindly points out, depending on which conditions cause termination, the server will send either a FIN or a RST. This change will remove the "amount read" based termination threshold, so that connections that cause failed handshakes will discard all data received until the teardown time is reached. Thanks to Sergey Frolov for bringing this issue to my attention. --- ChangeLog | 2 ++ transports/obfs4/obfs4.go | 26 +++++++++----------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 046eb41..ba5d1be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ Changes in version 0.0.11 - UNRELEASED: - Update my e-mail address. + - Change the obfs4 behavior for handling handshake failure to be more + uniform. Thanks to Sergey Frolov for assistance. Changes in version 0.0.10 - 2019-04-12: - Disable behavior distinctive to crypto/tls when using utls. diff --git a/transports/obfs4/obfs4.go b/transports/obfs4/obfs4.go index 0182a2c..9723735 100644 --- a/transports/obfs4/obfs4.go +++ b/transports/obfs4/obfs4.go @@ -34,6 +34,8 @@ import ( "crypto/sha256" "flag" "fmt" + "io" + "io/ioutil" "math/rand" "net" "strconv" @@ -67,9 +69,8 @@ const ( serverHandshakeTimeout = time.Duration(30) * time.Second replayTTL = time.Duration(3) * time.Hour - maxIATDelay = 100 - maxCloseDelayBytes = maxHandshakeLength - maxCloseDelay = 60 + maxIATDelay = 100 + maxCloseDelay = 60 ) const ( @@ -138,7 +139,7 @@ func (t *Transport) ServerFactory(stateDir string, args *pt.Args) (base.ServerFa } rng := rand.New(drbg) - sf := &obfs4ServerFactory{t, &ptArgs, st.nodeID, st.identityKey, st.drbgSeed, iatSeed, st.iatMode, filter, rng.Intn(maxCloseDelayBytes), rng.Intn(maxCloseDelay)} + sf := &obfs4ServerFactory{t, &ptArgs, st.nodeID, st.identityKey, st.drbgSeed, iatSeed, st.iatMode, filter, rng.Intn(maxCloseDelay)} return sf, nil } @@ -233,8 +234,7 @@ type obfs4ServerFactory struct { iatMode int replayFilter *replayfilter.ReplayFilter - closeDelayBytes int - closeDelay int + closeDelay int } func (sf *obfs4ServerFactory) Transport() base.Transport { @@ -592,17 +592,9 @@ func (conn *obfs4Conn) closeAfterDelay(sf *obfs4ServerFactory, startTime time.Ti return } - // Consume and discard data on this connection until either the specified - // interval passes or a certain size has been reached. - discarded := 0 - var buf [framing.MaximumSegmentLength]byte - for discarded < int(sf.closeDelayBytes) { - n, err := conn.Conn.Read(buf[:]) - if err != nil { - return - } - discarded += n - } + // Consume and discard data on this connection until the specified interval + // passes. + _, _ = io.Copy(ioutil.Discard, conn.Conn) } func (conn *obfs4Conn) padBurst(burst *bytes.Buffer, toPadTo int) (err error) {