check / check (push) Waiting to run
GeoJS's geo.json is asked about every new visitor unless SWWAF_LOOKUP_SOURCE is off. A request waits for its client's first answer only while a country list or SWWAF_ADD_LOOKUP_HEADERS needs it; otherwise the answer reaches the client's history and ban notes when it comes. The AS number and name go beside the country in the request log, history, ban notes, alerts and lookups.json, with metrics by AS number; 64512 counts as unknown. Judgement call: AS numbers are written AS64496, as SPEC's settings write them. Judgement call: SWWAF_LOOKUP_TIMEOUT is added, default 1s, and cannot be off. Judgement call: a client's own X-Client-* headers are removed only while SWWAF_ADD_LOOKUP_HEADERS is set. Model: opus-5-5
103 lines
2.5 KiB
Go
103 lines
2.5 KiB
Go
package lookup_test
|
|
|
|
import (
|
|
"net/netip"
|
|
"slices"
|
|
"testing"
|
|
"testing/synctest"
|
|
"time"
|
|
|
|
"sneak.berlin/go/smallwebwaf/internal/lookup"
|
|
)
|
|
|
|
func TestSnapshotHoldsEachAnswerAndWhenItWasLastUsed(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
synctest.Test(t, func(t *testing.T) {
|
|
_, clock, g := start()
|
|
placed := netip.MustParsePrefix("203.0.113.9/32")
|
|
notPlaced := netip.MustParsePrefix(unplaced + "/32")
|
|
asked := clock.Now()
|
|
|
|
wantCountry(t, g, placed, germany)
|
|
wantCountry(t, g, notPlaced, "")
|
|
|
|
clock.advance(time.Hour)
|
|
wantCountry(t, g, placed, germany)
|
|
|
|
want := []lookup.Answer{
|
|
{Client: notPlaced, Answered: asked, Used: asked},
|
|
{
|
|
Client: placed, ASN: asn, ASName: asName, Country: germany,
|
|
Answered: asked, Used: asked.Add(time.Hour),
|
|
},
|
|
}
|
|
if got := g.Snapshot(); !slices.Equal(got, want) {
|
|
t.Errorf("snapshot\n%+v\nwant\n%+v", got, want)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestLoadedAnswersAreKeptFor7DaysFromWhenGeoJSGaveThem(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
geojs, clock, g := start()
|
|
now := clock.Now()
|
|
kept := lookup.Answer{
|
|
Client: netip.MustParsePrefix("203.0.113.9/32"),
|
|
Country: "FR",
|
|
Answered: now.Add(-week + time.Second),
|
|
Used: now.Add(-time.Hour),
|
|
}
|
|
stale := lookup.Answer{
|
|
Client: netip.MustParsePrefix("203.0.113.10/32"),
|
|
Country: "FR",
|
|
Answered: now.Add(-week),
|
|
Used: now.Add(-time.Hour),
|
|
}
|
|
|
|
g.Load([]lookup.Answer{kept, stale})
|
|
|
|
if got := g.Snapshot(); !slices.Equal(got, []lookup.Answer{kept}) {
|
|
t.Errorf("kept %+v, want only the answer GeoJS gave less than 7 days ago", got)
|
|
}
|
|
|
|
wantCountry(t, g, kept.Client, "FR")
|
|
wantRequests(t, geojs, 0)
|
|
}
|
|
|
|
func TestLoadDropsTheAnswerUsedLongestAgoFirst(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const maxAnswers = 100000
|
|
|
|
_, clock, g := start()
|
|
now := clock.Now()
|
|
|
|
// lookups.json lists the answers by client. Here each was last used a
|
|
// second before the one listed before it, so the last listed is the
|
|
// one used longest ago, and the one dropped.
|
|
answers := make([]lookup.Answer, maxAnswers+1)
|
|
addr := netip.MustParseAddr("10.0.0.0")
|
|
|
|
for i := range answers {
|
|
answers[i] = lookup.Answer{
|
|
Client: netip.PrefixFrom(addr, addr.BitLen()),
|
|
Country: germany,
|
|
Answered: now,
|
|
Used: now.Add(-time.Duration(i) * time.Second),
|
|
}
|
|
addr = addr.Next()
|
|
}
|
|
|
|
g.Load(answers)
|
|
|
|
got := g.Snapshot()
|
|
if len(got) != maxAnswers || got[0] != answers[0] ||
|
|
got[maxAnswers-1] != answers[maxAnswers-1] {
|
|
t.Errorf("%d answers kept, from %s to %s; want %d, from %s to %s",
|
|
len(got), got[0].Client, got[len(got)-1].Client, maxAnswers,
|
|
answers[0].Client, answers[maxAnswers-1].Client)
|
|
}
|
|
}
|