121 lines
2.8 KiB
Go
121 lines
2.8 KiB
Go
package lib
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/google/cel-go/cel"
|
|
"github.com/google/cel-go/common/types"
|
|
"github.com/google/cel-go/common/types/ref"
|
|
"log/slog"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
func (state *State) initConditions() (err error) {
|
|
state.RulesEnv, err = cel.NewEnv(
|
|
cel.DefaultUTCTimeZone(true),
|
|
cel.Variable("remoteAddress", cel.BytesType),
|
|
cel.Variable("host", cel.StringType),
|
|
cel.Variable("method", cel.StringType),
|
|
cel.Variable("userAgent", cel.StringType),
|
|
cel.Variable("path", cel.StringType),
|
|
cel.Variable("query", cel.MapType(cel.StringType, cel.StringType)),
|
|
cel.Variable("fpJA3N", cel.StringType),
|
|
cel.Variable("fpJA4", cel.StringType),
|
|
// http.Header
|
|
cel.Variable("headers", cel.MapType(cel.StringType, cel.StringType)),
|
|
//TODO: dynamic type?
|
|
cel.Function("inDNSBL",
|
|
cel.Overload("inDNSBL_ip",
|
|
[]*cel.Type{cel.AnyType},
|
|
cel.BoolType,
|
|
cel.UnaryBinding(func(val ref.Val) ref.Val {
|
|
if state.Settings.DNSBL == nil {
|
|
return types.Bool(false)
|
|
}
|
|
|
|
var ip net.IP
|
|
switch v := val.Value().(type) {
|
|
case []byte:
|
|
ip = v
|
|
case net.IP:
|
|
ip = v
|
|
case string:
|
|
ip = net.ParseIP(v)
|
|
}
|
|
|
|
if ip == nil {
|
|
panic(fmt.Errorf("invalid ip %v", val.Value()))
|
|
}
|
|
|
|
var key [net.IPv6len]byte
|
|
copy(key[:], ip.To16())
|
|
|
|
result, ok := state.DecayMap.Get(key)
|
|
if ok {
|
|
return types.Bool(result.Bad())
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
defer cancel()
|
|
result, err := state.Settings.DNSBL.Lookup(ctx, ip)
|
|
if err != nil {
|
|
slog.Debug("dnsbl lookup failed", "address", ip.String(), "result", result, "err", err)
|
|
} else {
|
|
slog.Debug("dnsbl lookup", "address", ip.String(), "result", result)
|
|
}
|
|
//TODO: configure decay
|
|
state.DecayMap.Set(key, result, time.Hour)
|
|
|
|
return types.Bool(result.Bad())
|
|
}),
|
|
),
|
|
),
|
|
cel.Function("inNetwork",
|
|
cel.Overload("inNetwork_string_ip",
|
|
[]*cel.Type{cel.StringType, cel.AnyType},
|
|
cel.BoolType,
|
|
cel.BinaryBinding(func(lhs ref.Val, rhs ref.Val) ref.Val {
|
|
var ip net.IP
|
|
switch v := rhs.Value().(type) {
|
|
case []byte:
|
|
ip = v
|
|
case net.IP:
|
|
ip = v
|
|
case string:
|
|
ip = net.ParseIP(v)
|
|
}
|
|
|
|
if ip == nil {
|
|
panic(fmt.Errorf("invalid ip %v", rhs.Value()))
|
|
}
|
|
|
|
val, ok := lhs.Value().(string)
|
|
if !ok {
|
|
panic(fmt.Errorf("invalid value %v", lhs.Value()))
|
|
}
|
|
|
|
network, ok := state.Networks[val]
|
|
if !ok {
|
|
_, ipNet, err := net.ParseCIDR(val)
|
|
if err != nil {
|
|
panic("network not found")
|
|
}
|
|
return types.Bool(ipNet.Contains(ip))
|
|
} else {
|
|
ok, err := network.Contains(ip)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return types.Bool(ok)
|
|
}
|
|
}),
|
|
),
|
|
),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|