From efb9d17c8cb83eeecf3ccaa8cc34b647aabe4af5 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Sun, 18 May 2014 03:37:22 +0000 Subject: Change the server failure close delay/discard length to be consistent. It will vary per bridge as it is based off the DRBG, but ever attempt at poking at any given bridge will exhibit consistent behavior. --- obfs4.go | 27 +++++++++++++++------------ weighted_dist.go | 8 +++++--- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/obfs4.go b/obfs4.go index 8c4c46e..562015a 100644 --- a/obfs4.go +++ b/obfs4.go @@ -44,10 +44,8 @@ const ( headerLength = framing.FrameOverhead + packetOverhead connectionTimeout = time.Duration(30) * time.Second - minCloseThreshold = 0 - maxCloseThreshold = framing.MaximumSegmentLength * 5 - minCloseInterval = 0 - maxCloseInterval = 60 + maxCloseDelayBytes = framing.MaximumSegmentLength * 5 + maxCloseDelay = 60 ) type connState int @@ -77,6 +75,9 @@ type Obfs4Conn struct { // Server side state. listener *Obfs4Listener + startTime time.Time + closeDelayBytes int + closeDelay int } func (c *Obfs4Conn) padBurst(burst *bytes.Buffer) (err error) { @@ -116,11 +117,13 @@ func (c *Obfs4Conn) closeAfterDelay() { // I-it's not like I w-wanna handshake with you or anything. B-b-baka! defer c.conn.Close() - delaySecs := randRange(minCloseInterval, maxCloseInterval) - toDiscard := randRange(minCloseThreshold, maxCloseThreshold) + delay := time.Duration(c.closeDelay) * time.Second + deadline := c.startTime.Add(delay) + if time.Now().After(deadline) { + return + } - delay := time.Duration(delaySecs) * time.Second - err := c.conn.SetReadDeadline(time.Now().Add(delay)) + err := c.conn.SetReadDeadline(deadline) if err != nil { return } @@ -129,7 +132,7 @@ func (c *Obfs4Conn) closeAfterDelay() { // interval passes or a certain size has been reached. discarded := 0 var buf [framing.MaximumSegmentLength]byte - for discarded < int(toDiscard) { + for discarded < int(c.closeDelayBytes) { n, err := c.conn.Read(buf[:]) if err != nil { return @@ -324,9 +327,6 @@ func (c *Obfs4Conn) ServerHandshake() error { err := c.serverHandshake(c.listener.nodeID, c.listener.keyPair) c.listener = nil if err != nil { - // XXX: Maybe make the timeout period deterministic, since random - // hangup intervals are also suspicious. An ok value would be someting - // like the Nginx client_header_timeout (60s). c.closeAfterDelay() } @@ -544,6 +544,9 @@ func (l *Obfs4Listener) Accept() (net.Conn, error) { c.Close() return nil, err } + cObfs.startTime = time.Now() + cObfs.closeDelayBytes = cObfs.lenProbDist.rng.Intn(maxCloseDelayBytes) + cObfs.closeDelay = cObfs.lenProbDist.rng.Intn(maxCloseDelay) return cObfs, nil } diff --git a/weighted_dist.go b/weighted_dist.go index 067adaf..af0fa7d 100644 --- a/weighted_dist.go +++ b/weighted_dist.go @@ -136,6 +136,8 @@ type wDist struct { maxValue int values []int buckets []float64 + + rng *rand.Rand } // newWDist creates a weighted distribution of values ranging from min to max @@ -174,15 +176,15 @@ func (w *wDist) sample() int { func (w *wDist) reset(seed *DrbgSeed) { // Initialize the deterministic random number generator. drbg := newHashDrbg(seed) - dRng := rand.New(drbg) + w.rng = rand.New(drbg) nBuckets := (w.maxValue + 1) - w.minValue - w.values = dRng.Perm(nBuckets) + w.values = w.rng.Perm(nBuckets) w.buckets = make([]float64, nBuckets) var totalProb float64 for i, _ := range w.buckets { - prob := dRng.Float64() * (1.0 - totalProb) + prob := w.rng.Float64() * (1.0 - totalProb) w.buckets[i] = prob totalProb += prob } -- cgit v1.2.3