diff --git a/internal/server/auth.go b/internal/server/auth.go index 40eae1b..9cf0e70 100644 --- a/internal/server/auth.go +++ b/internal/server/auth.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/cbeuw/Cloak/internal/ecdh" "github.com/cbeuw/Cloak/internal/util" + "time" ) var ErrReplay = errors.New("duplicate random") @@ -50,7 +51,9 @@ func TouchStone(ch *ClientHello, sta *State) (UID []byte, sessionID uint32, prox proxyMethod = string(bytes.Trim(plaintext[16:28], "\x00")) encryptionMethod = plaintext[28] timestamp := int64(binary.BigEndian.Uint64(plaintext[29:37])) - if timestamp/int64(TIMESTAMP_WINDOW.Seconds()) != sta.Now().Unix()/int64(TIMESTAMP_WINDOW.Seconds()) { + clientTime := time.Unix(timestamp, 0) + serverTime := sta.Now() + if !(clientTime.After(serverTime.Truncate(TIMESTAMP_TOLERANCE)) && clientTime.Before(serverTime.Add(TIMESTAMP_TOLERANCE))) { err = fmt.Errorf("%v: received timestamp %v", ErrTimestampOutOfWindow, timestamp) return } diff --git a/internal/server/state.go b/internal/server/state.go index 6f80a44..0af7d4f 100644 --- a/internal/server/state.go +++ b/internal/server/state.go @@ -121,20 +121,18 @@ func (sta *State) IsBypass(UID []byte) bool { return exist } -// This is the accepting window of the encrypted timestamp from client -// we reject the client if the timestamp is outside of this window. -// This is for replay prevention so that we don't have to save unlimited amount of -// random -const TIMESTAMP_WINDOW = 12 * time.Hour +const TIMESTAMP_TOLERANCE = 180 * time.Second + +const CACHE_CLEAN_INTERVAL = 12 * time.Hour // UsedRandomCleaner clears the cache of used random fields every 12 hours func (sta *State) UsedRandomCleaner() { for { - time.Sleep(TIMESTAMP_WINDOW) - now := sta.Now().Unix() + time.Sleep(CACHE_CLEAN_INTERVAL) + now := sta.Now() sta.usedRandomM.Lock() for key, t := range sta.usedRandom { - if now-t > int64(TIMESTAMP_WINDOW.Seconds()) { + if time.Unix(t, 0).Before(now.Add(TIMESTAMP_TOLERANCE)) { delete(sta.usedRandom, key) } }