mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
https://github.com/XTLS/Xray-core/pull/5992#issuecomment-4320551920 Usage: https://github.com/XTLS/Xray-core/pull/5992#issuecomment-4291168039
136 lines
3.0 KiB
Go
136 lines
3.0 KiB
Go
package geodata
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"sync/atomic"
|
|
|
|
"github.com/xtls/xray-core/common/errors"
|
|
"github.com/xtls/xray-core/common/net"
|
|
)
|
|
|
|
type IPRegistry struct {
|
|
mu sync.Mutex
|
|
ipsetFactory *IPSetFactory
|
|
matchers []*DynamicIPMatcher
|
|
}
|
|
|
|
func (r *IPRegistry) BuildIPMatcher(rules []*IPRule) (IPMatcher, error) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
|
|
m, err := buildOptimizedIPMatcher(r.ipsetFactory, rules)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d := NewDynamicIPMatcher(rules, m)
|
|
r.matchers = append(r.matchers, d)
|
|
return d, nil
|
|
}
|
|
|
|
func (r *IPRegistry) Reload() error {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
|
|
errors.LogInfo(context.Background(), "reloading GeoIP data for ", len(r.matchers), " IP matcher(s)")
|
|
|
|
factory := newIPSetFactory()
|
|
type reloadEntry struct {
|
|
dynamic *DynamicIPMatcher
|
|
matcher IPMatcher
|
|
}
|
|
reloaded := make([]reloadEntry, len(r.matchers))
|
|
for i, d := range r.matchers {
|
|
m, err := buildOptimizedIPMatcher(factory, d.rules)
|
|
if err != nil {
|
|
errors.LogErrorInner(context.Background(), err, "failed to reload GeoIP data for IP matcher ", i)
|
|
return err
|
|
}
|
|
reloaded[i] = reloadEntry{dynamic: d, matcher: m}
|
|
}
|
|
for _, entry := range reloaded {
|
|
entry.dynamic.Reload(entry.matcher)
|
|
}
|
|
r.ipsetFactory = factory
|
|
errors.LogInfo(context.Background(), "reloaded GeoIP data for ", len(r.matchers), " IP matcher(s)")
|
|
return nil
|
|
}
|
|
|
|
func newIPRegistry() *IPRegistry {
|
|
return &IPRegistry{
|
|
ipsetFactory: newIPSetFactory(),
|
|
}
|
|
}
|
|
|
|
var IPReg = newIPRegistry()
|
|
|
|
type ipMatcherState struct {
|
|
matcher IPMatcher
|
|
}
|
|
|
|
type DynamicIPMatcher struct {
|
|
rules []*IPRule
|
|
state atomic.Pointer[ipMatcherState]
|
|
mu sync.Mutex
|
|
reverse bool
|
|
reverseSet bool
|
|
}
|
|
|
|
// Match implements IPMatcher.
|
|
func (d *DynamicIPMatcher) Match(ip net.IP) bool {
|
|
return d.state.Load().matcher.Match(ip)
|
|
}
|
|
|
|
// AnyMatch implements IPMatcher.
|
|
func (d *DynamicIPMatcher) AnyMatch(ips []net.IP) bool {
|
|
return d.state.Load().matcher.AnyMatch(ips)
|
|
}
|
|
|
|
// Matches implements IPMatcher.
|
|
func (d *DynamicIPMatcher) Matches(ips []net.IP) bool {
|
|
return d.state.Load().matcher.Matches(ips)
|
|
}
|
|
|
|
// FilterIPs implements IPMatcher.
|
|
func (d *DynamicIPMatcher) FilterIPs(ips []net.IP) (matched []net.IP, unmatched []net.IP) {
|
|
return d.state.Load().matcher.FilterIPs(ips)
|
|
}
|
|
|
|
// ToggleReverse implements IPMatcher.
|
|
func (d *DynamicIPMatcher) ToggleReverse() {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
d.reverse = !d.reverse
|
|
d.state.Load().matcher.ToggleReverse()
|
|
}
|
|
|
|
// SetReverse implements IPMatcher.
|
|
func (d *DynamicIPMatcher) SetReverse(reverse bool) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
d.reverse = reverse
|
|
d.reverseSet = true
|
|
d.state.Load().matcher.SetReverse(reverse)
|
|
}
|
|
|
|
func (d *DynamicIPMatcher) Reload(newMatcher IPMatcher) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
if d.reverseSet {
|
|
newMatcher.SetReverse(d.reverse)
|
|
} else if d.reverse {
|
|
newMatcher.ToggleReverse()
|
|
}
|
|
d.state.Store(&ipMatcherState{matcher: newMatcher})
|
|
}
|
|
|
|
func NewDynamicIPMatcher(rules []*IPRule, matcher IPMatcher) *DynamicIPMatcher {
|
|
d := &DynamicIPMatcher{rules: rules}
|
|
d.Reload(matcher)
|
|
return d
|
|
}
|