diff --git a/internal/acl/config.go b/internal/acl/config.go index 90fe152..4528707 100644 --- a/internal/acl/config.go +++ b/internal/acl/config.go @@ -7,6 +7,7 @@ import ( "github.com/puzpuzpuz/xsync/v3" "github.com/yusing/go-proxy/internal/common" "github.com/yusing/go-proxy/internal/gperr" + "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/logging/accesslog" "github.com/yusing/go-proxy/internal/maxmind" "github.com/yusing/go-proxy/internal/task" @@ -21,6 +22,7 @@ type Config struct { Log *accesslog.ACLLoggerConfig `json:"log"` config + valErr gperr.Error } type config struct { @@ -57,7 +59,8 @@ func (c *Config) Validate() gperr.Error { case ACLDeny: c.defaultAllow = false default: - return gperr.New("invalid default value").Subject(c.Default) + c.valErr = gperr.New("invalid default value").Subject(c.Default) + return c.valErr } if c.AllowLocal != nil { @@ -70,12 +73,17 @@ func (c *Config) Validate() gperr.Error { c.logAllowed = c.Log.LogAllowed } + if !c.allowLocal && !c.defaultAllow && len(c.Allow) == 0 { + c.valErr = gperr.New("allow_local is false and default is deny, but no allow rules are configured") + return c.valErr + } + c.ipCache = xsync.NewMapOf[string, *checkCache]() return nil } func (c *Config) Valid() bool { - return c != nil && (len(c.Allow) > 0 || len(c.Deny) > 0 || c.allowLocal) + return c != nil && c.valErr == nil } func (c *Config) Start(parent *task.Task) gperr.Error { @@ -86,6 +94,15 @@ func (c *Config) Start(parent *task.Task) gperr.Error { } c.logger = logger } + if c.valErr != nil { + return c.valErr + } + logging.Info(). + Str("default", c.Default). + Bool("allow_local", c.allowLocal). + Int("allow_rules", len(c.Allow)). + Int("deny_rules", len(c.Deny)). + Msg("ACL started") return nil } @@ -114,8 +131,7 @@ func (c *Config) IPAllowed(ip net.IP) bool { return false } - // always allow loopback - // loopback is not logged + // always allow loopback, not logged if ip.IsLoopback() { return true } diff --git a/internal/acl/matcher.go b/internal/acl/matcher.go index a9d99b4..19022c3 100644 --- a/internal/acl/matcher.go +++ b/internal/acl/matcher.go @@ -24,6 +24,9 @@ const ( MatcherTypeCountry = "country" ) +// TODO: use this error in the future +// +//nolint:unused var errMatcherFormat = gperr.Multiline().AddLines( "invalid matcher format, expect {type}:{value}", "Available types: ip|cidr|tz|country", @@ -34,10 +37,9 @@ var errMatcherFormat = gperr.Multiline().AddLines( ) var ( - errSyntax = errors.New("syntax error") - errInvalidIP = errors.New("invalid IP") - errInvalidCIDR = errors.New("invalid CIDR") - errMaxMindNotConfigured = errors.New("MaxMind not configured") + errSyntax = errors.New("syntax error") + errInvalidIP = errors.New("invalid IP") + errInvalidCIDR = errors.New("invalid CIDR") ) func (matcher *Matcher) Parse(s string) error { @@ -60,14 +62,8 @@ func (matcher *Matcher) Parse(s string) error { } matcher.match = matchCIDR(net) case MatcherTypeTimeZone: - if !maxmind.HasInstance() { - return errMaxMindNotConfigured - } matcher.match = matchTimeZone(parts[1]) case MatcherTypeCountry: - if !maxmind.HasInstance() { - return errMaxMindNotConfigured - } matcher.match = matchISOCode(parts[1]) default: return errSyntax diff --git a/internal/acl/udp_listener.go b/internal/acl/udp_listener.go index ac51ee4..d533833 100644 --- a/internal/acl/udp_listener.go +++ b/internal/acl/udp_listener.go @@ -10,12 +10,12 @@ type UDPListener struct { lis net.PacketConn } -func (cfg *Config) WrapUDP(lis net.PacketConn) net.PacketConn { - if cfg == nil { +func (c *Config) WrapUDP(lis net.PacketConn) net.PacketConn { + if c == nil { return lis } return &UDPListener{ - acl: cfg, + acl: c, lis: lis, } } diff --git a/internal/config/config.go b/internal/config/config.go index 044ee10..621cfa0 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -248,8 +248,6 @@ func (cfg *Config) load() gperr.Error { err := model.ACL.Start(cfg.task) if err != nil { errs.Add(err) - } else { - logging.Info().Msg("ACL started") } } diff --git a/internal/maxmind/instance.go b/internal/maxmind/instance.go index 96fbe73..3e30aec 100644 --- a/internal/maxmind/instance.go +++ b/internal/maxmind/instance.go @@ -1,12 +1,29 @@ package maxmind import ( + "sync" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "github.com/yusing/go-proxy/internal/gperr" + "github.com/yusing/go-proxy/internal/notif" "github.com/yusing/go-proxy/internal/task" ) var instance *MaxMind +var warnOnce sync.Once + +func warnNotConfigured() { + log.Warn().Msg("MaxMind not configured, geo lookup will fail") + notif.Notify(¬if.LogMessage{ + Level: zerolog.WarnLevel, + Title: "MaxMind not configured", + Body: notif.MessageBody("MaxMind is not configured, geo lookup will fail"), + Color: notif.ColorError, + }) +} + func SetInstance(parent task.Parent, cfg *Config) gperr.Error { newInstance := &MaxMind{Config: cfg} if err := newInstance.LoadMaxMindDB(parent); err != nil { @@ -22,6 +39,7 @@ func HasInstance() bool { func LookupCity(ip *IPInfo) (*City, bool) { if instance == nil { + warnOnce.Do(warnNotConfigured) return nil, false } return instance.lookupCity(ip)