diff options
author | Cecylia Bocovich <cohosh@torproject.org> | 2020-11-23 14:02:54 -0500 |
---|---|---|
committer | Cecylia Bocovich <cohosh@torproject.org> | 2020-12-04 11:17:13 -0500 |
commit | 114df695ceff25d0213200a3368ed7a1bb1c7668 (patch) | |
tree | bf8c3f548199ca5a0d31fb7d638af52fe6d7ef1e | |
parent | 5efcde518796e319231fd68c816e1ab74dd66129 (diff) | |
download | snowflake-114df695ceff25d0213200a3368ed7a1bb1c7668.tar.gz snowflake-114df695ceff25d0213200a3368ed7a1bb1c7668.zip |
Create new smux session for each SOCKS connection
Each SOCKS connection has its own set of snowflakes and broker poll
loop. Since the session manager was tied to a single set of snowflakes,
this resulted in a bug where RedialPacketConn would sometimes try to
pull snowflakes from a previously melted pool. The fix is to maintain
separate smux sessions for each SOCKS connection, tied to its own
snowflake pool.
-rw-r--r-- | client/lib/snowflake.go | 57 |
1 files changed, 6 insertions, 51 deletions
diff --git a/client/lib/snowflake.go b/client/lib/snowflake.go index e888160..171e173 100644 --- a/client/lib/snowflake.go +++ b/client/lib/snowflake.go @@ -6,7 +6,6 @@ import ( "io" "log" "net" - "sync" "time" "git.torproject.org/pluggable-transports/snowflake.git/common/turbotunnel" @@ -92,54 +91,6 @@ func newSession(snowflakes SnowflakeCollector) (net.PacketConn, *smux.Session, e return pconn, sess, err } -// sessionManager_ maintains a single global smux.Session that is shared among -// incoming SOCKS connections. -type sessionManager_ struct { - mutex sync.Mutex - sess *smux.Session -} - -// Get creates and returns a new global smux.Session if none exists yet. If one -// already exists, it returns the existing one. It monitors the returned session -// and if it ever fails, sets things up so the next call to Get will create a -// new session. -func (manager *sessionManager_) Get(snowflakes SnowflakeCollector) (*smux.Session, error) { - manager.mutex.Lock() - defer manager.mutex.Unlock() - - if manager.sess == nil { - log.Printf("starting a new session") - pconn, sess, err := newSession(snowflakes) - if err != nil { - return nil, err - } - manager.sess = sess - go func() { - // If the session dies, set it to be recreated. - for { - <-time.After(5 * time.Second) - if sess.IsClosed() { - break - } - } - log.Printf("discarding finished session") - // Close the underlying to force any ongoing WebRTC - // connection to close as well, and relinquish the - // SnowflakeCollector. - pconn.Close() - manager.mutex.Lock() - manager.sess = nil - manager.mutex.Unlock() - }() - } else { - log.Printf("reusing the existing session") - } - - return manager.sess, nil -} - -var sessionManager = sessionManager_{} - // Given an accepted SOCKS connection, establish a WebRTC connection to the // remote peer and exchange traffic. func Handler(socks net.Conn, tongue Tongue) error { @@ -155,8 +106,9 @@ func Handler(socks net.Conn, tongue Tongue) error { log.Printf("---- Handler: begin collecting snowflakes ---") go connectLoop(snowflakes) - // Return the global smux.Session. - sess, err := sessionManager.Get(snowflakes) + // Create a new smux session + log.Printf("---- Handler: starting a new session ---") + pconn, sess, err := newSession(snowflakes) if err != nil { return err } @@ -174,6 +126,9 @@ func Handler(socks net.Conn, tongue Tongue) error { log.Printf("---- Handler: closed stream %v ---", stream.ID()) snowflakes.End() log.Printf("---- Handler: end collecting snowflakes ---") + pconn.Close() + sess.Close() + log.Printf("---- Handler: discarding finished session ---") return nil } |