mirror of
https://github.com/putyy/res-downloader.git
synced 2026-01-12 14:14:55 +08:00
127 lines
2.3 KiB
Go
127 lines
2.3 KiB
Go
package core
|
||
|
||
import (
|
||
"bufio"
|
||
"net"
|
||
"strings"
|
||
"sync"
|
||
)
|
||
|
||
type Rule struct {
|
||
raw string
|
||
isNeg bool // 是否否定规则(以 ! 开头)
|
||
isWildcard bool // 是否为 *.domain 形式
|
||
isAll bool
|
||
domain string // 域名部分,不含 "*."
|
||
}
|
||
|
||
type RuleSet struct {
|
||
mu sync.RWMutex
|
||
rules []Rule
|
||
}
|
||
|
||
func initRule() *RuleSet {
|
||
if ruleOnce == nil {
|
||
ruleOnce = &RuleSet{}
|
||
err := ruleOnce.Load(globalConfig.Rule)
|
||
if err != nil {
|
||
globalLogger.Esg(err, "init rule failed")
|
||
return nil
|
||
}
|
||
}
|
||
return ruleOnce
|
||
}
|
||
|
||
func (r *RuleSet) Load(rs string) error {
|
||
reader := strings.NewReader(rs)
|
||
scanner := bufio.NewScanner(reader)
|
||
|
||
var rules []Rule
|
||
for scanner.Scan() {
|
||
line := strings.TrimSpace(scanner.Text())
|
||
if line == "" || strings.HasPrefix(line, "#") {
|
||
continue
|
||
}
|
||
|
||
isNeg := false
|
||
if strings.HasPrefix(line, "!") {
|
||
isNeg = true
|
||
line = strings.TrimSpace(line[1:])
|
||
if line == "" {
|
||
continue
|
||
}
|
||
}
|
||
|
||
if line == "*" {
|
||
rules = append(rules, Rule{
|
||
raw: "*",
|
||
isAll: true,
|
||
isNeg: isNeg,
|
||
})
|
||
continue
|
||
}
|
||
|
||
isWildcard := false
|
||
domain := line
|
||
if strings.HasPrefix(line, "*.") {
|
||
isWildcard = true
|
||
domain = line[2:]
|
||
}
|
||
|
||
rules = append(rules, Rule{
|
||
raw: line,
|
||
isNeg: isNeg,
|
||
isWildcard: isWildcard,
|
||
domain: strings.ToLower(domain),
|
||
})
|
||
}
|
||
|
||
if err := scanner.Err(); err != nil {
|
||
return err
|
||
}
|
||
|
||
r.mu.Lock()
|
||
r.rules = rules
|
||
r.mu.Unlock()
|
||
return nil
|
||
}
|
||
|
||
// shouldMitm: 根据当前规则集判断是否对 host 做 MITM
|
||
// host 可能带端口(example.com:443),函数会只匹配 hostname 部分
|
||
// 返回 true => MITM(解密),false => 透传
|
||
func (r *RuleSet) shouldMitm(host string) bool {
|
||
h := host
|
||
if strings.HasPrefix(h, "[") {
|
||
if hostSplitIdx := strings.LastIndex(h, "]"); hostSplitIdx != -1 {
|
||
h = h[:hostSplitIdx+1]
|
||
}
|
||
}
|
||
if hp, _, err := net.SplitHostPort(host); err == nil {
|
||
h = hp
|
||
}
|
||
h = strings.ToLower(strings.Trim(h, "[]"))
|
||
|
||
r.mu.RLock()
|
||
defer r.mu.RUnlock()
|
||
|
||
action := false
|
||
for _, rule := range r.rules {
|
||
if rule.isAll {
|
||
action = !rule.isNeg
|
||
continue
|
||
}
|
||
|
||
if rule.isWildcard {
|
||
if h == rule.domain || strings.HasSuffix(h, "."+rule.domain) {
|
||
action = !rule.isNeg
|
||
}
|
||
continue
|
||
}
|
||
|
||
if h == rule.domain {
|
||
action = !rule.isNeg
|
||
}
|
||
}
|
||
return action
|
||
}
|