Wildcard matched rules

This commit is contained in:
2025-04-07 11:42:37 +08:00
parent 5d7e37ab7c
commit a7ad598fc6
4 changed files with 183 additions and 7 deletions

View File

@ -1,6 +1,7 @@
package perm
import (
"encoding/json"
"errors"
"strconv"
"strings"
@ -59,6 +60,27 @@ func (a Action) MarshalText() ([]byte, error) {
return []byte(a.String()), nil
}
// globAction is a helper to pack globs better.
type globAction struct {
Glob string
Act Action
}
func (g *globAction) UnmarshalJSON(b []byte) error {
m := make(map[string]Action)
if err := json.Unmarshal(b, &m); err != nil {
return err
}
if len(m) != 1 {
return errors.New("Glob action object does not have & only have one key")
}
for k, v := range m {
g.Glob = k
g.Act = v
}
return nil
}
// Config is a list of address and actions, for each source address.
// It can just be Marshal/Unmarshaled into/from json.
type Config struct {
@ -70,6 +92,12 @@ type Config struct {
// Port number is extracted by net/url.splitHostPort, copied below.
// Port number is optional, but must be numeric when present.
Match map[string]Action
// Object which holds wildcard matches.
// This is searched after Match. It appends the default port if not found.
//
// Unlike Match, this is a list that is searched top-to-bottom.
MatchWildcard []globAction
}
// validOptionalPort reports whether port is either an empty string

View File

@ -6,11 +6,14 @@ import (
"strconv"
"strings"
"sync"
"edgaru089.ink/go/regolith/internal/util"
)
type int_perm struct {
match map[string]Action
def Action
match map[string]Action
match_glob []globAction
def Action
}
// Perm matches address:port strings to Actions
@ -77,6 +80,29 @@ func (p *Perm) Load(cs map[string]Config) {
}
}
}
for _, glob := range c.MatchWildcard {
addr, port := splitHostPort(glob.Glob)
if port != "" {
log.Printf("loading glob target %s, action %s", glob.Glob, glob.Act)
p_int.match_glob = append(
p_int.match_glob,
globAction{
Glob: glob.Glob,
Act: glob.Act,
})
} else {
// TODO change this to sth faster
for _, def_port := range c.DefaultPort {
log.Printf("loading glob target %s, action %s", net.JoinHostPort(addr, strconv.Itoa(def_port)), glob.Act)
p_int.match_glob = append(
p_int.match_glob,
globAction{
Glob: net.JoinHostPort(addr, strconv.Itoa(def_port)),
Act: glob.Act,
})
}
}
}
return
}
@ -108,9 +134,18 @@ func (p *Perm) Match(src, dest string) Action {
// find its source struct
p_int, ok_int := p.source[src]
// only check if dest is directly listed
if ok_int && p_int.match != nil {
if action, ok := p_int.match[dest]; ok {
return action
if ok_int {
// first check direct match
if p_int.match != nil {
if action, ok := p_int.match[dest]; ok {
return action
}
}
// then check glob match
for _, g := range p_int.match_glob {
if util.Match(g.Glob, dest) {
return g.Act
}
}
}
@ -120,6 +155,12 @@ func (p *Perm) Match(src, dest string) Action {
return action
}
}
// then check global glob match
for _, g := range p.global.match_glob {
if util.Match(g.Glob, dest) {
return g.Act
}
}
// directly listed in neither.
if ok_int {