diff options
Diffstat (limited to 'lib/policy/policy.go')
| -rw-r--r-- | lib/policy/policy.go | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/lib/policy/policy.go b/lib/policy/policy.go new file mode 100644 index 0000000..51b23ff --- /dev/null +++ b/lib/policy/policy.go @@ -0,0 +1,122 @@ +package policy + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net" + "regexp" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/yl2chen/cidranger" + + "github.com/TecharoHQ/anubis/lib/policy/config" +) + +var ( + PolicyApplications = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "anubis_policy_results", + Help: "The results of each policy rule", + }, []string{"rule", "action"}) +) + +type ParsedConfig struct { + orig config.Config + + Bots []Bot + DNSBL bool + DefaultDifficulty int +} + +func NewParsedConfig(orig config.Config) *ParsedConfig { + return &ParsedConfig{ + orig: orig, + } +} + +func ParseConfig(fin io.Reader, fname string, defaultDifficulty int) (*ParsedConfig, error) { + var c config.Config + if err := json.NewDecoder(fin).Decode(&c); err != nil { + return nil, fmt.Errorf("can't parse policy config JSON %s: %w", fname, err) + } + + if err := c.Valid(); err != nil { + return nil, err + } + + var err error + + result := NewParsedConfig(c) + result.DefaultDifficulty = defaultDifficulty + + for _, b := range c.Bots { + if berr := b.Valid(); berr != nil { + err = errors.Join(err, berr) + continue + } + + var botParseErr error + parsedBot := Bot{ + Name: b.Name, + Action: b.Action, + } + + if b.RemoteAddr != nil && len(b.RemoteAddr) > 0 { + parsedBot.Ranger = cidranger.NewPCTrieRanger() + + for _, cidr := range b.RemoteAddr { + _, rng, err := net.ParseCIDR(cidr) + if err != nil { + return nil, fmt.Errorf("[unexpected] range %s not parsing: %w", cidr, err) + } + + parsedBot.Ranger.Insert(cidranger.NewBasicRangerEntry(*rng)) + } + } + + if b.UserAgentRegex != nil { + userAgent, err := regexp.Compile(*b.UserAgentRegex) + if err != nil { + botParseErr = errors.Join(botParseErr, fmt.Errorf("while compiling user agent regexp: %w", err)) + continue + } else { + parsedBot.UserAgent = userAgent + } + } + + if b.PathRegex != nil { + path, err := regexp.Compile(*b.PathRegex) + if err != nil { + botParseErr = errors.Join(botParseErr, fmt.Errorf("while compiling path regexp: %w", err)) + continue + } else { + parsedBot.Path = path + } + } + + if b.Challenge == nil { + parsedBot.Challenge = &config.ChallengeRules{ + Difficulty: defaultDifficulty, + ReportAs: defaultDifficulty, + Algorithm: config.AlgorithmFast, + } + } else { + parsedBot.Challenge = b.Challenge + if parsedBot.Challenge.Algorithm == config.AlgorithmUnknown { + parsedBot.Challenge.Algorithm = config.AlgorithmFast + } + } + + result.Bots = append(result.Bots, parsedBot) + } + + if err != nil { + return nil, fmt.Errorf("errors validating policy config JSON %s: %w", fname, err) + } + + result.DNSBL = c.DNSBL + + return result, nil +} |
