|
@@ -20,39 +20,30 @@
|
|
|
package dtls
|
|
package dtls
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
- "net"
|
|
|
|
|
- "time"
|
|
|
|
|
|
|
+ "context"
|
|
|
|
|
|
|
|
"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
|
|
"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
|
|
|
"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
|
|
"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
|
|
|
- lrucache "github.com/cognusion/go-cache-lru"
|
|
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
-// dtlsSeedCacheTTL should be long enough for the seed to remain available in
|
|
|
|
|
-// the cache between when it's first set at the start of WebRTC operations,
|
|
|
|
|
-// and until all DTLS dials have completed.
|
|
|
|
|
|
|
+type dtlsSeedValue string
|
|
|
|
|
|
|
|
-const (
|
|
|
|
|
- dtlsSeedCacheTTL = 60 * time.Second
|
|
|
|
|
- dtlsSeedCacheMaxSize = 10000
|
|
|
|
|
-)
|
|
|
|
|
|
|
+const valueKey = dtlsSeedValue("DTLS-seed")
|
|
|
|
|
|
|
|
// SetDTLSSeed establishes a cached common/prng seed to be used when
|
|
// SetDTLSSeed establishes a cached common/prng seed to be used when
|
|
|
// randomizing DTLS Hellos.
|
|
// randomizing DTLS Hellos.
|
|
|
//
|
|
//
|
|
|
-// The seed is keyed by the specified conn's local address. This allows a fork
|
|
|
|
|
-// of pion/dtls to fetch the seed and apply randomization without having to
|
|
|
|
|
-// fork many pion layers to pass in seeds. Concurrent dials must use distinct
|
|
|
|
|
-// conns with distinct local addresses (including port number).
|
|
|
|
|
|
|
+// The seed is attached as a value to the input dial context, yielding the
|
|
|
|
|
+// output context. This allows a fork of pion/dtls to fetch the seed, from a
|
|
|
|
|
+// context, and apply randomization without having to fork many pion layers
|
|
|
|
|
+// to pass in seeds.
|
|
|
//
|
|
//
|
|
|
// Both sides of a WebRTC connection may randomize their Hellos. isOffer
|
|
// Both sides of a WebRTC connection may randomize their Hellos. isOffer
|
|
|
// allows the same seed to be used, but produce two distinct random streams.
|
|
// allows the same seed to be used, but produce two distinct random streams.
|
|
|
// The client generates or replays an obfuscation secret used to derive the
|
|
// The client generates or replays an obfuscation secret used to derive the
|
|
|
// seed, and the obfuscation secret is relayed to the proxy by the Broker.
|
|
// seed, and the obfuscation secret is relayed to the proxy by the Broker.
|
|
|
-//
|
|
|
|
|
-// The caller may specify TTL, which can be used to retain the cached key for
|
|
|
|
|
-// a dial timeout duration; when TTL is <= 0, a default TTL is used.
|
|
|
|
|
-func SetDTLSSeed(localAddr net.Addr, baseSeed *prng.Seed, isOffer bool, TTL time.Duration) error {
|
|
|
|
|
|
|
+func SetDTLSSeed(
|
|
|
|
|
+ ctx context.Context, baseSeed *prng.Seed, isOffer bool) (context.Context, error) {
|
|
|
|
|
|
|
|
salt := "inproxy-client-DTLS-seed"
|
|
salt := "inproxy-client-DTLS-seed"
|
|
|
if !isOffer {
|
|
if !isOffer {
|
|
@@ -61,48 +52,28 @@ func SetDTLSSeed(localAddr net.Addr, baseSeed *prng.Seed, isOffer bool, TTL time
|
|
|
|
|
|
|
|
seed, err := prng.NewSaltedSeed(baseSeed, salt)
|
|
seed, err := prng.NewSaltedSeed(baseSeed, salt)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- return errors.Trace(err)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if TTL <= 0 {
|
|
|
|
|
- TTL = lrucache.DefaultExpiration
|
|
|
|
|
|
|
+ return nil, errors.Trace(err)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // In the case where a previously used local port number is reused in a
|
|
|
|
|
- // new dial, this will replace the previous seed.
|
|
|
|
|
-
|
|
|
|
|
- dtlsSeedCache.Set(localAddr.String(), seed, TTL)
|
|
|
|
|
|
|
+ seedCtx := context.WithValue(ctx, valueKey, seed)
|
|
|
|
|
|
|
|
- return nil
|
|
|
|
|
|
|
+ return seedCtx, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// SetNoDTLSSeed indicates to skip DTLS randomization for the conn specified
|
|
|
|
|
-// by the local address.
|
|
|
|
|
-func SetNoDTLSSeed(localAddr net.Addr, TTL time.Duration) {
|
|
|
|
|
-
|
|
|
|
|
- if TTL <= 0 {
|
|
|
|
|
- TTL = lrucache.DefaultExpiration
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- dtlsSeedCache.Set(localAddr.String(), nil, TTL)
|
|
|
|
|
|
|
+// SetNoDTLSSeed indicates to skip DTLS randomization for the given dial
|
|
|
|
|
+// context.
|
|
|
|
|
+func SetNoDTLSSeed(ctx context.Context) context.Context {
|
|
|
|
|
+ var nilSeed *prng.Seed
|
|
|
|
|
+ return context.WithValue(ctx, valueKey, nilSeed)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// GetDTLSSeed fetches a seed established by SetDTLSSeed, or returns an error
|
|
|
|
|
-// if no seed is found for the specified conn, keyed by local/source address.
|
|
|
|
|
-func GetDTLSSeed(localAddr net.Addr) (*prng.Seed, error) {
|
|
|
|
|
- seed, ok := dtlsSeedCache.Get(localAddr.String())
|
|
|
|
|
- if !ok {
|
|
|
|
|
|
|
+// GetDTLSSeed fetches a seed established by SetDTLSSeed, or nil for no seed
|
|
|
|
|
+// as set by SetNoDTLSSeed, or returns an error if no seed is configured
|
|
|
|
|
+// specified dial context.
|
|
|
|
|
+func GetDTLSSeed(ctx context.Context) (*prng.Seed, error) {
|
|
|
|
|
+ value := ctx.Value(valueKey)
|
|
|
|
|
+ if value == nil {
|
|
|
return nil, errors.TraceNew("missing seed")
|
|
return nil, errors.TraceNew("missing seed")
|
|
|
}
|
|
}
|
|
|
- if seed == nil {
|
|
|
|
|
- return nil, nil
|
|
|
|
|
- }
|
|
|
|
|
- return seed.(*prng.Seed), nil
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-var dtlsSeedCache *lrucache.Cache
|
|
|
|
|
-
|
|
|
|
|
-func init() {
|
|
|
|
|
- dtlsSeedCache = lrucache.NewWithLRU(
|
|
|
|
|
- dtlsSeedCacheTTL, 1*time.Minute, dtlsSeedCacheMaxSize)
|
|
|
|
|
|
|
+ return value.(*prng.Seed), nil
|
|
|
}
|
|
}
|