Add DNSBL querying in conditions

This commit is contained in:
WeebDataHoarder
2025-04-08 22:11:58 +02:00
parent 285090c9c1
commit ce111f6ae9
8 changed files with 254 additions and 11 deletions

View File

@@ -1,11 +1,14 @@
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) {
@@ -20,6 +23,52 @@ func (state *State) initConditions() (err error) {
// 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},

View File

@@ -26,6 +26,7 @@ import (
"io"
"io/fs"
"log/slog"
"net"
"net/http"
"net/http/httputil"
"net/url"
@@ -60,6 +61,10 @@ type State struct {
Poison map[string][]byte
ChallengeSolve sync.Map
DecayMap *utils.DecayMap[[net.IPv6len]byte, utils.DNSBLResponse]
close chan struct{}
}
func (state *State) AwaitChallenge(key []byte, ctx context.Context) challenge.VerifyResult {
@@ -107,10 +112,12 @@ type StateSettings struct {
ChallengeTemplate string
ChallengeTemplateTheme string
ClientIpHeader string
DNSBL *utils.DNSBL
}
func NewState(p policy.Policy, settings StateSettings) (state *State, err error) {
state = new(State)
func NewState(p policy.Policy, settings StateSettings) (handler http.Handler, err error) {
state := new(State)
state.close = make(chan struct{})
state.Settings = settings
state.Client = &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
@@ -119,6 +126,10 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error)
}
state.UrlPath = "/.well-known/." + state.Settings.PackageName
if state.Settings.DNSBL != nil {
state.DecayMap = utils.NewDecayMap[[net.IPv6len]byte, utils.DNSBLResponse]()
}
// set a reasonable configuration for default http proxy if there is none
for _, backend := range state.Settings.Backends {
if proxy, ok := backend.(*httputil.ReverseProxy); ok {
@@ -220,6 +231,7 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error)
idCounter := challenge.Id(1)
//TODO: move this to self-contained challenge files
for challengeName, p := range p.Challenges {
// allow nesting
@@ -769,6 +781,20 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error)
return nil, err
}
if state.DecayMap != nil {
go func() {
ticker := time.NewTicker(17 * time.Minute)
for {
select {
case <-ticker.C:
state.DecayMap.Decay()
case <-state.close:
return
}
}
}()
}
return state, nil
}