Skip to content

Commit 71ea7c4

Browse files
authored
Merge pull request #1287 from projectdiscovery/feature/eviction-strategy
Eviction Strategy
2 parents 97201ec + 1b8cef1 commit 71ea7c4

6 files changed

Lines changed: 83 additions & 5 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ INPUT:
346346
-lip, -listen-ip string public ip address to listen on (default "0.0.0.0")
347347
-e, -eviction int number of days to persist interaction data in memory (default 30)
348348
-ne, -no-eviction disable periodic data eviction from memory
349+
-es, -eviction-strategy string eviction strategy for interactions (sliding, fixed) (default "sliding")
349350
-a, -auth enable authentication to server using random generated token
350351
-t, -token string enable authentication to server using given token
351352
-acao-url string origin url to send in acao header to use web-client) (default "*")

cmd/interactsh-server/main.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func main() {
4949
flagSet.StringVarP(&cliOptions.ListenIP, "listen-ip", "lip", "0.0.0.0", "public ip address to listen on"),
5050
flagSet.IntVarP(&cliOptions.Eviction, "eviction", "e", 30, "number of days to persist interaction data in memory"),
5151
flagSet.BoolVarP(&cliOptions.NoEviction, "no-eviction", "ne", false, "disable periodic data eviction from memory"),
52+
flagSet.StringVarP(&cliOptions.EvictionStrategy, "eviction-strategy", "es", "sliding", "eviction strategy for interactions (sliding, fixed)"),
5253
flagSet.BoolVarP(&cliOptions.Auth, "auth", "a", false, "enable authentication to server using random generated token"),
5354
flagSet.StringVarP(&cliOptions.Token, "token", "t", "", "enable authentication to server using given token"),
5455
flagSet.StringVar(&cliOptions.OriginURL, "acao-url", "*", "origin url to send in acao header to use web-client)"), // cli flag set to deprecate
@@ -230,9 +231,22 @@ func main() {
230231
if cliOptions.NoEviction {
231232
evictionTTL = -1
232233
}
234+
235+
// Parse eviction strategy
236+
var evictionStrategy storage.EvictionStrategy
237+
switch strings.ToLower(cliOptions.EvictionStrategy) {
238+
case "fixed":
239+
evictionStrategy = storage.EvictionStrategyFixed
240+
case "sliding":
241+
evictionStrategy = storage.EvictionStrategySliding
242+
default:
243+
gologger.Fatal().Msgf("invalid eviction strategy '%s', must be 'sliding' or 'fixed'\n", cliOptions.EvictionStrategy)
244+
}
245+
233246
var store storage.Storage
234247
storeOptions := storage.DefaultOptions
235248
storeOptions.EvictionTTL = evictionTTL
249+
storeOptions.EvictionStrategy = evictionStrategy
236250
if cliOptions.DiskStorage {
237251
if cliOptions.DiskStoragePath == "" {
238252
gologger.Fatal().Msgf("disk storage path must be specified\n")

pkg/options/server_options.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type CLIServerOptions struct {
2323
LdapWithFullLogger bool
2424
Eviction int
2525
NoEviction bool
26+
EvictionStrategy string
2627
Responder bool
2728
Smb bool
2829
SmbPort int

pkg/storage/option.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@ package storage
22

33
import "time"
44

5+
type EvictionStrategy int
6+
7+
const (
8+
EvictionStrategySliding EvictionStrategy = iota // expire-after-access
9+
EvictionStrategyFixed // expire-after-write
10+
)
11+
512
type Options struct {
6-
DbPath string
7-
EvictionTTL time.Duration
8-
MaxSize int
13+
DbPath string
14+
EvictionTTL time.Duration
15+
MaxSize int
16+
EvictionStrategy EvictionStrategy
917
}
1018

1119
func (options *Options) UseDisk() bool {
1220
return options.DbPath != ""
1321
}
1422

1523
var DefaultOptions = Options{
16-
MaxSize: 2500000,
24+
MaxSize: 2500000,
25+
EvictionStrategy: EvictionStrategySliding,
1726
}

pkg/storage/storagedb.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,14 @@ func New(options *Options) (*StorageDB, error) {
3737
cache.WithMaximumSize(options.MaxSize),
3838
}
3939
if options.EvictionTTL > 0 {
40-
cacheOptions = append(cacheOptions, cache.WithExpireAfterAccess(options.EvictionTTL))
40+
switch options.EvictionStrategy {
41+
case EvictionStrategyFixed:
42+
cacheOptions = append(cacheOptions, cache.WithExpireAfterWrite(options.EvictionTTL))
43+
case EvictionStrategySliding:
44+
fallthrough
45+
default:
46+
cacheOptions = append(cacheOptions, cache.WithExpireAfterAccess(options.EvictionTTL))
47+
}
4148
}
4249
if options.UseDisk() {
4350
cacheOptions = append(cacheOptions, cache.WithRemovalListener(storageDB.OnCacheRemovalCallback))

pkg/storage/storagedb_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,49 @@ func doStuffWithOtherCache(cache cache.Cache) {
133133
_, _ = cache.GetIfPresent(strconv.Itoa(i))
134134
}
135135
}
136+
137+
func TestSlidingEvictionStrategy(t *testing.T) {
138+
testTTL := 100 * time.Millisecond
139+
smallDelay := 10 * time.Millisecond
140+
mem, err := New(&Options{EvictionTTL: testTTL, EvictionStrategy: EvictionStrategySliding})
141+
require.Nil(t, err)
142+
defer mem.Close()
143+
144+
err = mem.SetID("test-sliding")
145+
require.Nil(t, err)
146+
147+
// Access after half TTL - should extend expiration
148+
time.Sleep(testTTL / 2)
149+
_, ok := mem.cache.GetIfPresent("test-sliding")
150+
require.True(t, ok)
151+
152+
// Still present after original TTL due to sliding window
153+
time.Sleep(testTTL / 2 + smallDelay)
154+
_, ok = mem.cache.GetIfPresent("test-sliding")
155+
require.True(t, ok)
156+
157+
// Should be expired after full TTL despite access
158+
time.Sleep(testTTL + smallDelay)
159+
_, ok = mem.cache.GetIfPresent("test-sliding")
160+
require.False(t, ok)
161+
}
162+
163+
func TestFixedEvictionStrategy(t *testing.T) {
164+
testTTL := 100 * time.Millisecond
165+
mem, err := New(&Options{EvictionTTL: testTTL, EvictionStrategy: EvictionStrategyFixed})
166+
require.Nil(t, err)
167+
defer mem.Close()
168+
169+
err = mem.SetID("test-fixed")
170+
require.Nil(t, err)
171+
172+
// Access after half TTL - should NOT extend expiration
173+
time.Sleep(testTTL / 2)
174+
_, ok := mem.cache.GetIfPresent("test-fixed")
175+
require.True(t, ok)
176+
177+
// Should be expired after full TTL despite access
178+
time.Sleep(testTTL / 2 + 10 * time.Millisecond)
179+
_, ok = mem.cache.GetIfPresent("test-fixed")
180+
require.False(t, ok)
181+
}

0 commit comments

Comments
 (0)