Look clients up in the IPinfo Lite file with SWWAF_LOOKUP_SOURCE=file (closes #22)
check / check (push) Waiting to run
check / check (push) Waiting to run
SWWAF_LOOKUP_SOURCE=file looks every client up in the file SWWAF_LOOKUP_DB_PATH names, without GeoJS. file without the path, the path with another source, or a file that cannot be read stops the start. The file is read whole into memory, so overwriting it in place cannot disturb a lookup, and read again 2 seconds after its last change; a replacement that cannot be read is logged, counted and sent as a file_error alert, and the old one stays in use. Metrics give when it was read and the failed reads. Tests write their databases through internal/lookup/lookuptest. Deviation: go.mod and go.sum written by hand; go runs only through make. Judgement call: the 2-second wait, as the rule files have. Model: opus-5-5
This commit was merged in pull request #98.
This commit is contained in:
@@ -92,12 +92,16 @@ type Config struct {
|
||||
// Each starts with /.
|
||||
RateLimitExemptPaths []string
|
||||
// LookupSource is where each client's AS number and country are
|
||||
// looked up (SWWAF_LOOKUP_SOURCE): geojs, or off for nowhere. A request
|
||||
// waits up to LookupTimeout for its client's first answer while a
|
||||
// setting needs it (SWWAF_LOOKUP_TIMEOUT), which cannot be off.
|
||||
// AddLookupHeaders is true when the app is passed the client's AS
|
||||
// number and country in headers (SWWAF_ADD_LOOKUP_HEADERS).
|
||||
// looked up (SWWAF_LOOKUP_SOURCE): geojs, file, or off for nowhere.
|
||||
// LookupDBPath is the lookup database, the IPinfo Lite file looked up
|
||||
// in while LookupSource is file (SWWAF_LOOKUP_DB_PATH), and "" for any
|
||||
// other source. A request waits up to LookupTimeout for its client's
|
||||
// first answer from GeoJS while a setting needs it
|
||||
// (SWWAF_LOOKUP_TIMEOUT), which cannot be off. AddLookupHeaders is true
|
||||
// when the app is passed the client's AS number and country in headers
|
||||
// (SWWAF_ADD_LOOKUP_HEADERS).
|
||||
LookupSource string
|
||||
LookupDBPath string
|
||||
LookupTimeout time.Duration
|
||||
AddLookupHeaders bool
|
||||
// DeniedCountries are the countries whose clients are refused
|
||||
@@ -201,6 +205,10 @@ type Config struct {
|
||||
// off.
|
||||
const off = "off"
|
||||
|
||||
// fileSource is the SWWAF_LOOKUP_SOURCE that looks clients up in the
|
||||
// lookup database, the file SWWAF_LOOKUP_DB_PATH names.
|
||||
const fileSource = "file"
|
||||
|
||||
const (
|
||||
day = 24 * time.Hour
|
||||
kibibyte = 1 << 10
|
||||
@@ -242,8 +250,10 @@ var (
|
||||
"is taken out of every request by Go's HTTP server, so it can never " +
|
||||
"be logged")
|
||||
errOnBothLists = errors.New("is in SWWAF_DENIED_COUNTRIES too")
|
||||
errNotLookupSource = errors.New("is not geojs or off")
|
||||
errNotLookupSource = errors.New("is not geojs, file or off")
|
||||
errNeedsLookups = errors.New("it needs each client looked up")
|
||||
errNeedsDBPath = errors.New("it names the file to look clients up in")
|
||||
errDBPathUnused = errors.New("only file reads it")
|
||||
errNotOver4K = errors.New("is not a size of more than 4K, such as 32K")
|
||||
errNotDurationAboveZero = errors.New(
|
||||
"is not a duration above zero, such as 1h or 7d")
|
||||
@@ -312,6 +322,7 @@ func FromEnvironment(lookupEnv func(string) (string, bool)) (*Config, error) {
|
||||
RateLimitPerDay: env.count("SWWAF_RATE_LIMIT_PER_DAY", "50000"),
|
||||
RateLimitExemptPaths: env.pathPrefixes("SWWAF_RATE_LIMIT_EXEMPT_PATHS", ""),
|
||||
LookupSource: env.lookupSource("SWWAF_LOOKUP_SOURCE", "geojs"),
|
||||
LookupDBPath: env.value("SWWAF_LOOKUP_DB_PATH", ""),
|
||||
LookupTimeout: env.durationNotOff("SWWAF_LOOKUP_TIMEOUT", "1s"),
|
||||
AddLookupHeaders: env.boolean("SWWAF_ADD_LOOKUP_HEADERS", "false"),
|
||||
DeniedCountries: env.countries("SWWAF_DENIED_COUNTRIES", ""),
|
||||
@@ -353,6 +364,7 @@ func FromEnvironment(lookupEnv func(string) (string, bool)) (*Config, error) {
|
||||
cfg.InstanceName, cfg.LogRemoteURL != nil)
|
||||
|
||||
env.checkInstanceNameForNtfy(cfg.InstanceName, cfg.AlertNtfyURL != nil)
|
||||
env.checkLookupDBPath(cfg)
|
||||
env.checkCountriesAndLookups(cfg)
|
||||
|
||||
if env.err != nil {
|
||||
@@ -556,16 +568,30 @@ func (e *environment) countries(name, defaultValue string) []string {
|
||||
}
|
||||
|
||||
// lookupSource reads the setting that is where clients are looked up:
|
||||
// geojs, or off.
|
||||
// geojs, file, or off.
|
||||
func (e *environment) lookupSource(name, defaultValue string) string {
|
||||
source := e.value(name, defaultValue)
|
||||
if source != "geojs" && source != off {
|
||||
if source != "geojs" && source != fileSource && source != off {
|
||||
e.check(name, fmt.Errorf("%q %w", source, errNotLookupSource))
|
||||
}
|
||||
|
||||
return source
|
||||
}
|
||||
|
||||
// checkLookupDBPath refuses SWWAF_LOOKUP_SOURCE=file without
|
||||
// SWWAF_LOOKUP_DB_PATH, and SWWAF_LOOKUP_DB_PATH with any other source:
|
||||
// one source at a time.
|
||||
func (e *environment) checkLookupDBPath(cfg *Config) {
|
||||
switch {
|
||||
case cfg.LookupSource == fileSource && cfg.LookupDBPath == "":
|
||||
e.check("SWWAF_LOOKUP_SOURCE", fmt.Errorf(
|
||||
"is file while SWWAF_LOOKUP_DB_PATH is unset; %w", errNeedsDBPath))
|
||||
case cfg.LookupSource != fileSource && cfg.LookupDBPath != "":
|
||||
e.check("SWWAF_LOOKUP_DB_PATH", fmt.Errorf(
|
||||
"is set while SWWAF_LOOKUP_SOURCE is %s; %w", cfg.LookupSource, errDBPathUnused))
|
||||
}
|
||||
}
|
||||
|
||||
// checkCountriesAndLookups refuses a country on both country lists, and,
|
||||
// while SWWAF_LOOKUP_SOURCE is off, each setting that needs clients looked
|
||||
// up: the country lists and SWWAF_ADD_LOOKUP_HEADERS.
|
||||
|
||||
Reference in New Issue
Block a user