From 34ad883559c5491efc85706b2c78603a895a1826 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Mon, 11 Nov 2019 14:59:09 +0300 Subject: [PATCH] Use ristretto instead of bigcache --- antireplay/cache.go | 30 +++++++++++++++++++++--------- antireplay/hasher.go | 9 --------- antireplay/init.go | 33 ++++++++++++--------------------- config/config.go | 9 ++------- faketls/client_protocol.go | 9 +++++++++ go.mod | 5 +---- go.sum | 14 ++++---------- main.go | 12 +++--------- obfuscated2/client_protocol.go | 6 +++--- 9 files changed, 55 insertions(+), 72 deletions(-) delete mode 100644 antireplay/hasher.go diff --git a/antireplay/cache.go b/antireplay/cache.go index a142bd9..72ca30e 100644 --- a/antireplay/cache.go +++ b/antireplay/cache.go @@ -1,26 +1,38 @@ package antireplay -import "github.com/allegro/bigcache" +import "github.com/dgraph-io/ristretto" + +var ( + prefixObfuscated2 = []byte{0x00} + prefixTLS = []byte{0x01} +) type cache struct { - obfuscated2 *bigcache.BigCache - tls *bigcache.BigCache + data *ristretto.Cache } func (c *cache) AddObfuscated2(data []byte) { - c.obfuscated2.Set(string(data), nil) // nolint: errcheck + c.data.Set(keyObfuscated2(data), nil, int64(len(data))) } func (c *cache) AddTLS(data []byte) { - c.tls.Set(string(data), nil) // nolint: errcheck + c.data.Set(keyTLS(data), nil, int64(len(data))) } func (c *cache) HasObfuscated2(data []byte) bool { - _, err := c.obfuscated2.Get(string(data)) - return err == nil + _, ok := c.data.Get(keyObfuscated2(data)) + return ok } func (c *cache) HasTLS(data []byte) bool { - _, err := c.tls.Get(string(data)) - return err == nil + _, ok := c.data.Get(keyTLS(data)) + return ok +} + +func keyObfuscated2(data []byte) string { + return string(append(prefixObfuscated2, data...)) +} + +func keyTLS(data []byte) string { + return string(append(prefixTLS, data...)) } diff --git a/antireplay/hasher.go b/antireplay/hasher.go deleted file mode 100644 index acaf9b6..0000000 --- a/antireplay/hasher.go +++ /dev/null @@ -1,9 +0,0 @@ -package antireplay - -import "github.com/cespare/xxhash" - -type hasher struct{} - -func (h hasher) Sum64(value string) uint64 { - return xxhash.Sum64String(value) -} diff --git a/antireplay/init.go b/antireplay/init.go index 740fa6f..5659ab7 100644 --- a/antireplay/init.go +++ b/antireplay/init.go @@ -1,42 +1,33 @@ package antireplay import ( + "math" "sync" "github.com/9seconds/mtg/config" - "github.com/allegro/bigcache" + "github.com/dgraph-io/ristretto" ) var ( - Cache *cache + Cache cache initOnce sync.Once ) func Init() { initOnce.Do(func() { - c1, err := bigcache.NewBigCache(bigcache.Config{ - Shards: 1024, - LifeWindow: config.C.AntiReplayEvictionTime, - Hasher: hasher{}, - HardMaxCacheSize: config.C.AntiReplayMaxSize, + cost := float64(config.C.AntiReplayMaxSize) / 32.0 + cost = math.Ceil(cost) + + c, err := ristretto.NewCache(&ristretto.Config{ + NumCounters: int64(cost) * 10, + MaxCost: config.C.AntiReplayMaxSize, + BufferItems: 64, + Metrics: false, }) if err != nil { panic(err) } - c2, err := bigcache.NewBigCache(bigcache.Config{ - Shards: 1024, - LifeWindow: config.C.AntiReplayEvictionTime, - Hasher: hasher{}, - HardMaxCacheSize: config.C.AntiReplayMaxSize, - }) - if err != nil { - panic(err) - } - - Cache = &cache{ - obfuscated2: c1, - tls: c2, - } + Cache.data = c }) } diff --git a/config/config.go b/config/config.go index dc4db73..e79f07e 100644 --- a/config/config.go +++ b/config/config.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "net" - "time" "github.com/alecthomas/units" "go.uber.org/zap" @@ -58,7 +57,6 @@ const ( OptionTypeCloakPort OptionTypeAntiReplayMaxSize - OptionTypeAntiReplayEvictionTime OptionTypeSecret OptionTypeAdtag @@ -80,8 +78,7 @@ type Config struct { ReadBuffer int `json:"read_buffer"` CloakPort int `json:"cloak_port"` - AntiReplayMaxSize int `json:"anti_replay_max_size"` - AntiReplayEvictionTime time.Duration `json:"anti_replay_eviction_time"` + AntiReplayMaxSize int64 `json:"anti_replay_max_size"` Debug bool `json:"debug"` Verbose bool `json:"verbose"` @@ -151,9 +148,7 @@ func Init(options ...Opt) error { // nolint: gocyclo, funlen case OptionTypeCloakPort: C.CloakPort = int(opt.Value.(uint16)) case OptionTypeAntiReplayMaxSize: - C.AntiReplayMaxSize = opt.Value.(int) - case OptionTypeAntiReplayEvictionTime: - C.AntiReplayEvictionTime = opt.Value.(time.Duration) + C.AntiReplayMaxSize = int64(opt.Value.(units.Base2Bytes)) case OptionTypeSecret: C.Secret = opt.Value.([]byte) case OptionTypeAdtag: diff --git a/faketls/client_protocol.go b/faketls/client_protocol.go index f0b82b2..a0cb209 100644 --- a/faketls/client_protocol.go +++ b/faketls/client_protocol.go @@ -11,10 +11,12 @@ import ( "sync" "time" + "github.com/9seconds/mtg/antireplay" "github.com/9seconds/mtg/config" "github.com/9seconds/mtg/conntypes" "github.com/9seconds/mtg/obfuscated2" "github.com/9seconds/mtg/protocol" + "github.com/9seconds/mtg/stats" "github.com/9seconds/mtg/tlstypes" "github.com/9seconds/mtg/wrappers/stream" ) @@ -82,6 +84,13 @@ func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error { return errBadTime } + if antireplay.Cache.HasTLS(clientHello.Random[:]) { + stats.Stats.ReplayDetected() + return errors.New("replay attack is detected") + } + + antireplay.Cache.AddTLS(clientHello.Random[:]) + hostCert, err := connectionServerInstance.get() if err != nil { return fmt.Errorf("cannot get host certificate: %w", err) diff --git a/go.mod b/go.mod index 8c7a5d2..7264d9f 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,10 @@ module github.com/9seconds/mtg replace github.com/golang/lint => github.com/golang/lint v0.0.0-20190227174305-8f45f776aaf1 require ( - github.com/OneOfOne/xxhash v1.2.5 // indirect github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d - github.com/allegro/bigcache v1.2.1 github.com/beevik/ntp v0.2.0 - github.com/cespare/xxhash v1.1.0 + github.com/dgraph-io/ristretto v0.0.0-20191108194154-8d6a8a75b4ca github.com/prometheus/client_golang v1.2.1 - github.com/spaolacci/murmur3 v1.1.0 // indirect go.uber.org/multierr v1.4.0 // indirect go.uber.org/zap v1.12.0 golang.org/x/crypto v0.0.0-20191106202628-ed6320f186d4 diff --git a/go.sum b/go.sum index 741a398..e7a8a98 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,5 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= -github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= @@ -13,8 +10,6 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1C github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= -github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= @@ -23,13 +18,15 @@ github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgraph-io/ristretto v0.0.0-20191108194154-8d6a8a75b4ca h1:NgFAOh7RDM5WbdADm6VyLG1koLrzG0G24M/f5395PcI= +github.com/dgraph-io/ristretto v0.0.0-20191108194154-8d6a8a75b4ca/go.mod h1:edzKIzGvqUCMzhTVWbiTSe75zD9Xxq0GtSBtFmaUTZs= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -94,9 +91,6 @@ github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= diff --git a/main.go b/main.go index 169f834..bbded3d 100644 --- a/main.go +++ b/main.go @@ -104,15 +104,10 @@ var ( Default("443"). Uint16() runAntiReplayMaxSize = runCommand.Flag("anti-replay-max-size", - "Max size of antireplay cache in megabytes."). + "Max size of antireplay cache."). Envar("MTG_ANTIREPLAY_MAXSIZE"). - Default("128"). - Int() - runAntiReplayEvictionTime = runCommand.Flag("anti-replay-eviction-time", - "Eviction time period for obfuscated2 handshakes"). - Envar("MTG_ANTIREPLAY_EVICTIONTIME"). - Default("168h"). - Duration() + Default("128MB"). + Bytes() runSecret = runCommand.Arg("secret", "Secret of this proxy.").Required().HexBytes() runAdtag = runCommand.Arg("adtag", "ADTag of the proxy.").HexBytes() ) @@ -146,7 +141,6 @@ func main() { config.Opt{Option: config.OptionTypeReadBufferSize, Value: *runReadBufferSize}, config.Opt{Option: config.OptionTypeCloakPort, Value: *runTLSCloakPort}, config.Opt{Option: config.OptionTypeAntiReplayMaxSize, Value: *runAntiReplayMaxSize}, - config.Opt{Option: config.OptionTypeAntiReplayEvictionTime, Value: *runAntiReplayEvictionTime}, config.Opt{Option: config.OptionTypeSecret, Value: *runSecret}, config.Opt{Option: config.OptionTypeAdtag, Value: *runAdtag}, ) diff --git a/obfuscated2/client_protocol.go b/obfuscated2/client_protocol.go index ec96807..d85387c 100644 --- a/obfuscated2/client_protocol.go +++ b/obfuscated2/client_protocol.go @@ -81,13 +81,13 @@ func (c *ClientProtocol) Handshake(socket conntypes.StreamReadWriteCloser) (conn c.dc = conntypes.DCDefaultIdx } - replayKeys := decryptedFrame.Unique() - if antireplay.Cache.HasObfuscated2(replayKeys) { + replayKey := decryptedFrame.Unique() + if antireplay.Cache.HasObfuscated2(replayKey) { stats.Stats.ReplayDetected() return nil, errors.New("replay attack is detected") } - antireplay.Cache.AddObfuscated2(replayKeys) + antireplay.Cache.AddObfuscated2(replayKey) return stream.NewObfuscated2(socket, encryptor, decryptor), nil }