package domain import ( "crypto/subtle" "errors" "fmt" "time" ) const ( ProbeFreshness = 30 * time.Second ProbeFutureSkew = 5 * time.Second MaxOpaqueLocationBytes = 512 DiscrepancyWindow = 24 * time.Hour DiscrepancyLimit = 3 CleanSamplesToRelease = 5 ) var ( ErrInvalidProbe = errors.New("invalid latency probe evidence") ErrProbeQuarantined = errors.New("latency samples are quarantined") ) // ProbeEvidence deliberately treats Steam's location as opaque. The backend // validates freshness/nonce and computes RTT from its own receive timestamps; // no client-provided RTT is used for placement. type ProbeEvidence struct { OpaqueLocation []byte Nonce []byte IssuedAt time.Time Region string ServerRTT time.Duration } func ValidateProbe(evidence ProbeEvidence, expectedNonce []byte, now time.Time) error { if len(evidence.OpaqueLocation) == 0 || len(evidence.OpaqueLocation) > MaxOpaqueLocationBytes || len(expectedNonce) == 0 { return ErrInvalidProbe } if len(evidence.Nonce) != len(expectedNonce) || subtle.ConstantTimeCompare(evidence.Nonce, expectedNonce) != 1 { return fmt.Errorf("%w: nonce mismatch", ErrInvalidProbe) } if evidence.IssuedAt.After(now.Add(ProbeFutureSkew)) || now.Sub(evidence.IssuedAt) > ProbeFreshness { return fmt.Errorf("%w: stale or future timestamp", ErrInvalidProbe) } if evidence.Region != "EU" && evidence.Region != "NA" { return fmt.Errorf("%w: unsupported region", ErrInvalidProbe) } if evidence.ServerRTT < 0 { return fmt.Errorf("%w: negative RTT", ErrInvalidProbe) } return nil } type DiscrepancyTracker struct { BadSamples []time.Time CleanSamples int Quarantined bool } // RecordComparison compares backend-computed predicted and observed RTT. A // discrepancy is over 25 ms or 30% (whichever is larger). Three bad samples // in 24 hours quarantine placement evidence; five clean samples release it. func (tracker *DiscrepancyTracker) RecordComparison(predicted, observed time.Duration, now time.Time) { tracker.prune(now) maxAllowed := 25 * time.Millisecond if predicted > 0 { percent := time.Duration(float64(predicted) * 0.30) if percent > maxAllowed { maxAllowed = percent } } delta := predicted - observed if delta < 0 { delta = -delta } if delta > maxAllowed { tracker.BadSamples = append(tracker.BadSamples, now) tracker.CleanSamples = 0 if len(tracker.BadSamples) >= DiscrepancyLimit { tracker.Quarantined = true } return } if tracker.Quarantined { tracker.CleanSamples++ if tracker.CleanSamples >= CleanSamplesToRelease { tracker.Quarantined = false tracker.BadSamples = nil tracker.CleanSamples = 0 } } } func (tracker *DiscrepancyTracker) prune(now time.Time) { cutoff := now.Add(-DiscrepancyWindow) kept := tracker.BadSamples[:0] for _, sample := range tracker.BadSamples { if !sample.Before(cutoff) { kept = append(kept, sample) } } tracker.BadSamples = kept } func (tracker DiscrepancyTracker) PlacementAllowed() error { if tracker.Quarantined { return ErrProbeQuarantined } return nil }