Merge branch 'main' into dev

This commit is contained in:
nadoo 2026-10-09 20:33:31 +08:00
commit 37444b8fb9
2 changed files with 31 additions and 16 deletions

View File

@ -103,6 +103,9 @@ cidr=192.168.100.0/24
include=office.list.example include=office.list.example
``` ```
When a destination matches domain rules in multiple rule groups, Glider uses the most specific matching domain (the longest matching domain suffix). For example, a rule for `service.example.com` takes precedence over a rule for `example.com` for requests to `service.example.com` and its subdomains, regardless of the order in which those rule files are loaded. Other subdomains of `example.com` continue to match the broader rule.
See: See:
- [office.rule.example](rules.d/office.rule.example) - [office.rule.example](rules.d/office.rule.example)
- [examples](examples) - [examples](examples)

View File

@ -28,7 +28,7 @@ func NewProxy(mainForwarders []string, mainStrategy *Strategy, rules []*Config)
rd.all = append(rd.all, group) rd.all = append(rd.all, group)
for _, domain := range r.Domain { for _, domain := range r.Domain {
rd.domainMap.Store(strings.ToLower(domain), group) rd.domainMap.Store(normalizeDomain(domain), group)
} }
for _, s := range r.IP { for _, s := range r.IP {
@ -59,7 +59,7 @@ func NewProxy(mainForwarders []string, mainStrategy *Strategy, rules []*Config)
addr, _, _ := strings.Cut(f.addr, ",") addr, _, _ := strings.Cut(f.addr, ",")
host, _, _ := net.SplitHostPort(addr) host, _, _ := net.SplitHostPort(addr)
if _, err := netip.ParseAddr(host); err != nil { if _, err := netip.ParseAddr(host); err != nil {
rd.domainMap.Store(strings.ToLower(host), direct) rd.domainMap.Store(normalizeDomain(host), direct)
} }
} }
} }
@ -105,18 +105,35 @@ func (p *Proxy) findDialer(dstAddr string) *FwdrGroup {
} }
} }
// check host // Check the full host before its parent domains so the most specific
host = strings.ToLower(host) // matching rule wins (for example, a.example.com before example.com).
for i := len(host); i != -1; { if group, ok := p.findDomainGroup(host); ok {
i = strings.LastIndexByte(host[:i], '.') return group
if proxy, ok := p.domainMap.Load(host[i+1:]); ok {
return proxy.(*FwdrGroup)
}
} }
return p.main return p.main
} }
func normalizeDomain(domain string) string {
return strings.TrimSuffix(strings.ToLower(domain), ".")
}
// findDomainGroup finds the most specific group matching domain.
func (p *Proxy) findDomainGroup(domain string) (*FwdrGroup, bool) {
domain = normalizeDomain(domain)
for {
if group, ok := p.domainMap.Load(domain); ok {
return group.(*FwdrGroup), true
}
dot := strings.IndexByte(domain, '.')
if dot == -1 {
return nil, false
}
domain = domain[dot+1:]
}
}
// NextDialer returns next dialer according to rule. // NextDialer returns next dialer according to rule.
func (p *Proxy) NextDialer(dstAddr string) proxy.Dialer { func (p *Proxy) NextDialer(dstAddr string) proxy.Dialer {
return p.findDialer(dstAddr).NextDialer(dstAddr) return p.findDialer(dstAddr).NextDialer(dstAddr)
@ -135,13 +152,8 @@ func (p *Proxy) Record(dialer proxy.Dialer, success bool) {
// AddDomainIP used to update ipMap rules according to domainMap rule. // AddDomainIP used to update ipMap rules according to domainMap rule.
func (p *Proxy) AddDomainIP(domain string, ip netip.Addr) error { func (p *Proxy) AddDomainIP(domain string, ip netip.Addr) error {
domain = strings.ToLower(domain) if group, ok := p.findDomainGroup(domain); ok {
for i := len(domain); i != -1; { p.ipMap.Store(ip, group)
i = strings.LastIndexByte(domain[:i], '.')
if dialer, ok := p.domainMap.Load(domain[i+1:]); ok {
p.ipMap.Store(ip, dialer)
// log.F("[rule] update map: %s/%s based on rule: domain=%s\n", domain, ip, domain[i+1:])
}
} }
return nil return nil
} }