summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYawning Angel <yawning@schwanenlied.me>2014-05-18 03:37:22 +0000
committerYawning Angel <yawning@schwanenlied.me>2014-05-18 03:37:22 +0000
commitefb9d17c8cb83eeecf3ccaa8cc34b647aabe4af5 (patch)
tree62b12ab6d83a15382005fe132cd7861b0d7f7e53
parent745d414645872853fe1e3adab28dfb02f0b61dd0 (diff)
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.
-rw-r--r--obfs4.go27
-rw-r--r--weighted_dist.go8
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
}