fix: acl matcher parsing, refactor

This commit is contained in:
yusing 2025-05-13 19:40:43 +08:00
parent 1e24765b17
commit 44b4cff35e
2 changed files with 35 additions and 33 deletions

View file

@ -133,19 +133,15 @@ func (c *Config) IPAllowed(ip net.IP) bool {
} }
ipAndStr := &maxmind.IPInfo{IP: ip, Str: ipStr} ipAndStr := &maxmind.IPInfo{IP: ip, Str: ipStr}
for _, m := range c.Allow { if c.Allow.Match(ipAndStr) {
if m(ipAndStr) { c.log(ipAndStr, true)
c.log(ipAndStr, true) c.cacheRecord(ipAndStr, true)
c.cacheRecord(ipAndStr, true) return true
return true
}
} }
for _, m := range c.Deny { if c.Deny.Match(ipAndStr) {
if m(ipAndStr) { c.log(ipAndStr, false)
c.log(ipAndStr, false) c.cacheRecord(ipAndStr, false)
c.cacheRecord(ipAndStr, false) return false
return false
}
} }
c.log(ipAndStr, c.defaultAllow) c.log(ipAndStr, c.defaultAllow)

View file

@ -1,6 +1,7 @@
package acl package acl
import ( import (
"errors"
"net" "net"
"strings" "strings"
@ -8,7 +9,11 @@ import (
"github.com/yusing/go-proxy/internal/maxmind" "github.com/yusing/go-proxy/internal/maxmind"
) )
type Matcher func(*maxmind.IPInfo) bool type MatcherFunc func(*maxmind.IPInfo) bool
type Matcher struct {
match MatcherFunc
}
type Matchers []Matcher type Matchers []Matcher
@ -29,68 +34,69 @@ var errMatcherFormat = gperr.Multiline().AddLines(
) )
var ( var (
errSyntax = gperr.New("syntax error") errSyntax = errors.New("syntax error")
errInvalidIP = gperr.New("invalid IP") errInvalidIP = errors.New("invalid IP")
errInvalidCIDR = gperr.New("invalid CIDR") errInvalidCIDR = errors.New("invalid CIDR")
errMaxMindNotConfigured = gperr.New("MaxMind not configured") errMaxMindNotConfigured = errors.New("MaxMind not configured")
) )
func ParseMatcher(s string) (Matcher, gperr.Error) { func (matcher *Matcher) Parse(s string) error {
parts := strings.Split(s, ":") parts := strings.Split(s, ":")
if len(parts) != 2 { if len(parts) != 2 {
return nil, errSyntax return errSyntax
} }
switch parts[0] { switch parts[0] {
case MatcherTypeIP: case MatcherTypeIP:
ip := net.ParseIP(parts[1]) ip := net.ParseIP(parts[1])
if ip == nil { if ip == nil {
return nil, errInvalidIP return errInvalidIP
} }
return matchIP(ip), nil matcher.match = matchIP(ip)
case MatcherTypeCIDR: case MatcherTypeCIDR:
_, net, err := net.ParseCIDR(parts[1]) _, net, err := net.ParseCIDR(parts[1])
if err != nil { if err != nil {
return nil, errInvalidCIDR return errInvalidCIDR
} }
return matchCIDR(net), nil matcher.match = matchCIDR(net)
case MatcherTypeTimeZone: case MatcherTypeTimeZone:
if !maxmind.HasInstance() { if !maxmind.HasInstance() {
return nil, errMaxMindNotConfigured return errMaxMindNotConfigured
} }
return matchTimeZone(parts[1]), nil matcher.match = matchTimeZone(parts[1])
case MatcherTypeCountry: case MatcherTypeCountry:
if !maxmind.HasInstance() { if !maxmind.HasInstance() {
return nil, errMaxMindNotConfigured return errMaxMindNotConfigured
} }
return matchISOCode(parts[1]), nil matcher.match = matchISOCode(parts[1])
default: default:
return nil, errSyntax return errSyntax
} }
return nil
} }
func (matchers Matchers) Match(ip *maxmind.IPInfo) bool { func (matchers Matchers) Match(ip *maxmind.IPInfo) bool {
for _, m := range matchers { for _, m := range matchers {
if m(ip) { if m.match(ip) {
return true return true
} }
} }
return false return false
} }
func matchIP(ip net.IP) Matcher { func matchIP(ip net.IP) MatcherFunc {
return func(ip2 *maxmind.IPInfo) bool { return func(ip2 *maxmind.IPInfo) bool {
return ip.Equal(ip2.IP) return ip.Equal(ip2.IP)
} }
} }
func matchCIDR(n *net.IPNet) Matcher { func matchCIDR(n *net.IPNet) MatcherFunc {
return func(ip *maxmind.IPInfo) bool { return func(ip *maxmind.IPInfo) bool {
return n.Contains(ip.IP) return n.Contains(ip.IP)
} }
} }
func matchTimeZone(tz string) Matcher { func matchTimeZone(tz string) MatcherFunc {
return func(ip *maxmind.IPInfo) bool { return func(ip *maxmind.IPInfo) bool {
city, ok := maxmind.LookupCity(ip) city, ok := maxmind.LookupCity(ip)
if !ok { if !ok {
@ -100,7 +106,7 @@ func matchTimeZone(tz string) Matcher {
} }
} }
func matchISOCode(iso string) Matcher { func matchISOCode(iso string) MatcherFunc {
return func(ip *maxmind.IPInfo) bool { return func(ip *maxmind.IPInfo) bool {
city, ok := maxmind.LookupCity(ip) city, ok := maxmind.LookupCity(ip)
if !ok { if !ok {