github.com/yaling888/clash@v1.53.0/config/config.go (about) 1 package config 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "net/netip" 8 "net/url" 9 "os" 10 "regexp" 11 "runtime" 12 "strings" 13 14 "github.com/phuslu/log" 15 "github.com/samber/lo" 16 "gopkg.in/yaml.v3" 17 18 "github.com/yaling888/clash/adapter" 19 "github.com/yaling888/clash/adapter/outbound" 20 "github.com/yaling888/clash/adapter/outboundgroup" 21 "github.com/yaling888/clash/adapter/provider" 22 "github.com/yaling888/clash/component/auth" 23 "github.com/yaling888/clash/component/fakeip" 24 "github.com/yaling888/clash/component/geodata" 25 "github.com/yaling888/clash/component/geodata/router" 26 _ "github.com/yaling888/clash/component/geodata/standard" 27 "github.com/yaling888/clash/component/resolver" 28 S "github.com/yaling888/clash/component/script" 29 "github.com/yaling888/clash/component/trie" 30 C "github.com/yaling888/clash/constant" 31 providerTypes "github.com/yaling888/clash/constant/provider" 32 "github.com/yaling888/clash/dns" 33 L "github.com/yaling888/clash/log" 34 "github.com/yaling888/clash/mitm" 35 R "github.com/yaling888/clash/rule" 36 T "github.com/yaling888/clash/tunnel" 37 ) 38 39 // General config 40 type General struct { 41 LegacyInbound 42 Controller 43 Authentication []string `json:"authentication"` 44 Mode T.TunnelMode `json:"mode"` 45 LogLevel L.LogLevel `json:"log-level"` 46 IPv6 bool `json:"ipv6"` 47 Sniffing bool `json:"sniffing"` 48 Interface string `json:"-"` 49 RoutingMark int `json:"-"` 50 Tun C.Tun `json:"tun"` 51 EBpf EBpf `json:"-"` 52 } 53 54 // LegacyInbound config 55 type LegacyInbound struct { 56 Port int `json:"port"` 57 SocksPort int `json:"socks-port"` 58 RedirPort int `json:"redir-port"` 59 TProxyPort int `json:"tproxy-port"` 60 MixedPort int `json:"mixed-port"` 61 MitmPort int `json:"mitm-port"` 62 AllowLan bool `json:"allow-lan"` 63 BindAddress string `json:"bind-address"` 64 } 65 66 // Controller config 67 type Controller struct { 68 ExternalController string `json:"-"` 69 ExternalUI string `json:"-"` 70 Secret string `json:"-"` 71 PPROF bool `json:"-"` 72 } 73 74 // DNS config 75 type DNS struct { 76 Enable bool `yaml:"enable"` 77 IPv6 bool `yaml:"ipv6"` 78 RemoteDnsResolve bool `yaml:"remote-dns-resolve"` 79 NameServer []dns.NameServer `yaml:"nameserver"` 80 Fallback []dns.NameServer `yaml:"fallback"` 81 ProxyServerNameserver []dns.NameServer `yaml:"proxy-server-nameserver"` 82 RemoteNameserver []dns.NameServer `yaml:"remote-nameserver"` 83 FallbackFilter FallbackFilter `yaml:"fallback-filter"` 84 Listen string `yaml:"listen"` 85 EnhancedMode C.DNSMode `yaml:"enhanced-mode"` 86 DefaultNameserver []dns.NameServer `yaml:"default-nameserver"` 87 FakeIPRange *fakeip.Pool 88 Hosts *trie.DomainTrie[netip.Addr] 89 NameServerPolicy map[string]dns.NameServer 90 SearchDomains []string 91 } 92 93 // FallbackFilter config 94 type FallbackFilter struct { 95 GeoIP bool `yaml:"geoip"` 96 GeoIPCode string `yaml:"geoip-code"` 97 IPCIDR []*netip.Prefix `yaml:"ipcidr"` 98 Domain []string `yaml:"domain"` 99 GeoSite []*router.DomainMatcher `yaml:"geosite"` 100 } 101 102 // Profile config 103 type Profile struct { 104 StoreSelected bool `yaml:"store-selected"` 105 StoreFakeIP bool `yaml:"store-fake-ip"` 106 Tracing bool `yaml:"tracing"` 107 } 108 109 // Script config 110 type Script struct { 111 Engine string `yaml:"engine" json:"engine"` 112 MainCode string `yaml:"code" json:"code"` 113 MainPath string `yaml:"path" json:"path"` 114 ShortcutsCode map[string]string `yaml:"shortcuts" json:"shortcuts"` 115 } 116 117 // Mitm config 118 type Mitm struct { 119 Hosts *trie.DomainTrie[bool] `yaml:"hosts" json:"hosts"` 120 Rules C.RewriteRule `yaml:"rules" json:"rules"` 121 } 122 123 // EBpf config 124 type EBpf struct { 125 RedirectToTun []string `yaml:"redirect-to-tun" json:"redirect-to-tun"` 126 AutoRedir []string `yaml:"auto-redir" json:"auto-redir"` 127 } 128 129 // Experimental config 130 type Experimental struct { 131 UDPFallbackMatch bool `yaml:"udp-fallback-match"` 132 UDPFallbackPolicy string `yaml:"udp-fallback-policy"` 133 } 134 135 // Config is clash config manager 136 type Config struct { 137 General *General 138 Mitm *Mitm 139 DNS *DNS 140 Experimental *Experimental 141 Hosts *trie.DomainTrie[netip.Addr] 142 Profile *Profile 143 Inbounds []C.Inbound 144 Rules []C.Rule 145 RuleProviders map[string]C.Rule 146 Users []auth.AuthUser 147 Proxies map[string]C.Proxy 148 Providers map[string]providerTypes.ProxyProvider 149 MainMatcher C.Matcher 150 Tunnels []Tunnel 151 } 152 153 type RawDNS struct { 154 Enable bool `yaml:"enable"` 155 IPv6 *bool `yaml:"ipv6"` 156 RemoteDnsResolve bool `yaml:"remote-dns-resolve"` 157 UseHosts bool `yaml:"use-hosts"` 158 NameServer []string `yaml:"nameserver"` 159 Fallback []string `yaml:"fallback"` 160 FallbackFilter RawFallbackFilter `yaml:"fallback-filter"` 161 Listen string `yaml:"listen"` 162 EnhancedMode C.DNSMode `yaml:"enhanced-mode"` 163 FakeIPRange string `yaml:"fake-ip-range"` 164 FakeIPFilter []string `yaml:"fake-ip-filter"` 165 DefaultNameserver []string `yaml:"default-nameserver"` 166 NameServerPolicy map[string]string `yaml:"nameserver-policy"` 167 ProxyServerNameserver []string `yaml:"proxy-server-nameserver"` 168 SearchDomains []string `yaml:"search-domains"` 169 RemoteNameserver []string `yaml:"remote-nameserver"` 170 } 171 172 type RawFallbackFilter struct { 173 GeoIP bool `yaml:"geoip"` 174 GeoIPCode string `yaml:"geoip-code"` 175 IPCIDR []string `yaml:"ipcidr"` 176 Domain []string `yaml:"domain"` 177 GeoSite []string `yaml:"geosite"` 178 } 179 180 type RawMitm struct { 181 Hosts []string `yaml:"hosts" json:"hosts"` 182 Rules []string `yaml:"rules" json:"rules"` 183 } 184 185 type tunnel struct { 186 Network []string `yaml:"network"` 187 Address string `yaml:"address"` 188 Target string `yaml:"target"` 189 Proxy string `yaml:"proxy"` 190 } 191 192 type Tunnel tunnel 193 194 // UnmarshalYAML implements yaml.Unmarshaler 195 func (t *Tunnel) UnmarshalYAML(unmarshal func(any) error) error { 196 var tp string 197 if err := unmarshal(&tp); err != nil { 198 var inner tunnel 199 if err := unmarshal(&inner); err != nil { 200 return err 201 } 202 203 *t = Tunnel(inner) 204 return nil 205 } 206 207 // parse udp/tcp,address,target,proxy 208 parts := lo.Map(strings.Split(tp, ","), func(s string, _ int) string { 209 return strings.TrimSpace(s) 210 }) 211 if len(parts) != 4 { 212 return fmt.Errorf("invalid tunnel config %s", tp) 213 } 214 network := strings.Split(parts[0], "/") 215 216 // validate network 217 for _, n := range network { 218 switch n { 219 case "tcp", "udp": 220 default: 221 return fmt.Errorf("invalid tunnel network %s", n) 222 } 223 } 224 225 // validate address and target 226 address := parts[1] 227 target := parts[2] 228 for _, addr := range []string{address, target} { 229 if _, _, err := net.SplitHostPort(addr); err != nil { 230 return fmt.Errorf("invalid tunnel target or address %s", addr) 231 } 232 } 233 234 *t = Tunnel(tunnel{ 235 Network: network, 236 Address: address, 237 Target: target, 238 Proxy: parts[3], 239 }) 240 return nil 241 } 242 243 type rawRule struct { 244 If string `yaml:"if"` 245 Name string `yaml:"name"` 246 Engine string `yaml:"engine"` 247 Rules []RawRule `yaml:"rules"` 248 Line string `yaml:"-"` 249 } 250 251 type RawRule rawRule 252 253 // UnmarshalYAML implements yaml.Unmarshaler 254 func (r *RawRule) UnmarshalYAML(unmarshal func(any) error) error { 255 var line string 256 if err := unmarshal(&line); err != nil { 257 inner := rawRule{ 258 Engine: "expr", 259 } 260 if err = unmarshal(&inner); err != nil { 261 return err 262 } 263 264 if inner.Name == "" { 265 return fmt.Errorf("invalid rule name") 266 } 267 268 if inner.If == "" { 269 return fmt.Errorf("invalid rule %s if", inner.Name) 270 } 271 272 if inner.Engine != "expr" && inner.Engine != "starlark" { 273 return fmt.Errorf("invalid rule %s engine, got %s, want expr or starlark", inner.Name, inner.Engine) 274 } 275 276 if len(inner.Rules) == 0 { 277 return fmt.Errorf("rule %s sub-rules can not be empty", inner.Name) 278 } 279 280 *r = RawRule(inner) 281 return nil 282 } 283 284 *r = RawRule(rawRule{ 285 Line: line, 286 }) 287 return nil 288 } 289 290 type RawConfig struct { 291 Port int `yaml:"port"` 292 SocksPort int `yaml:"socks-port"` 293 RedirPort int `yaml:"redir-port"` 294 TProxyPort int `yaml:"tproxy-port"` 295 MixedPort int `yaml:"mixed-port"` 296 MitmPort int `yaml:"mitm-port"` 297 Authentication []string `yaml:"authentication"` 298 AllowLan bool `yaml:"allow-lan"` 299 BindAddress string `yaml:"bind-address"` 300 Mode T.TunnelMode `yaml:"mode"` 301 LogLevel L.LogLevel `yaml:"log-level"` 302 IPv6 bool `yaml:"ipv6"` 303 ExternalController string `yaml:"external-controller"` 304 ExternalUI string `yaml:"external-ui"` 305 Secret string `yaml:"secret"` 306 PPROF bool `yaml:"pprof"` 307 Interface string `yaml:"interface-name"` 308 RoutingMark int `yaml:"routing-mark"` 309 Sniffing bool `yaml:"sniffing"` 310 ForceCertVerify bool `yaml:"force-cert-verify"` 311 Tunnels []Tunnel `yaml:"tunnels"` 312 313 ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` 314 Hosts map[string]string `yaml:"hosts"` 315 Inbounds []C.Inbound `yaml:"inbounds"` 316 DNS RawDNS `yaml:"dns"` 317 Tun C.Tun `yaml:"tun"` 318 MITM RawMitm `yaml:"mitm"` 319 Experimental Experimental `yaml:"experimental"` 320 Profile Profile `yaml:"profile"` 321 Proxy []C.RawProxy `yaml:"proxies"` 322 ProxyGroup []map[string]any `yaml:"proxy-groups"` 323 Rule []RawRule `yaml:"rules"` 324 Script Script `yaml:"script"` 325 EBpf EBpf `yaml:"ebpf"` 326 } 327 328 // Parse config 329 func Parse(buf []byte) (*Config, error) { 330 rawCfg, err := UnmarshalRawConfig(buf) 331 if err != nil { 332 return nil, err 333 } 334 335 return ParseRawConfig(rawCfg) 336 } 337 338 func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { 339 // config with default value 340 rawCfg := &RawConfig{ 341 AllowLan: false, 342 Sniffing: false, 343 ForceCertVerify: false, 344 BindAddress: "*", 345 Mode: T.Rule, 346 Authentication: []string{}, 347 LogLevel: L.INFO, 348 Hosts: map[string]string{}, 349 Rule: []RawRule{}, 350 Proxy: []C.RawProxy{}, 351 ProxyGroup: []map[string]any{}, 352 Tun: C.Tun{ 353 Enable: false, 354 Device: "", 355 Stack: C.TunGvisor, 356 DNSHijack: []C.DNSUrl{ // default hijack all dns lookup 357 { 358 Network: "udp", 359 AddrPort: C.DNSAddrPort{ 360 AddrPort: netip.MustParseAddrPort("0.0.0.0:53"), 361 }, 362 }, 363 { 364 Network: "tcp", 365 AddrPort: C.DNSAddrPort{ 366 AddrPort: netip.MustParseAddrPort("0.0.0.0:53"), 367 }, 368 }, 369 }, 370 AutoRoute: false, 371 AutoDetectInterface: false, 372 }, 373 EBpf: EBpf{ 374 RedirectToTun: []string{}, 375 AutoRedir: []string{}, 376 }, 377 DNS: RawDNS{ 378 Enable: false, 379 UseHosts: true, 380 RemoteDnsResolve: true, 381 FakeIPRange: "198.18.0.1/16", 382 FallbackFilter: RawFallbackFilter{ 383 GeoIP: true, 384 GeoIPCode: "CN", 385 IPCIDR: []string{}, 386 GeoSite: []string{}, 387 }, 388 DefaultNameserver: []string{ 389 "114.114.114.114", 390 "8.8.8.8", 391 }, 392 RemoteNameserver: []string{ 393 "tcp://1.1.1.1", 394 "tcp://8.8.8.8", 395 }, 396 }, 397 MITM: RawMitm{ 398 Hosts: []string{}, 399 Rules: []string{}, 400 }, 401 Profile: Profile{ 402 StoreSelected: true, 403 Tracing: true, 404 }, 405 Script: Script{ 406 Engine: "expr", 407 }, 408 } 409 410 if err := yaml.Unmarshal(buf, rawCfg); err != nil { 411 return nil, err 412 } 413 414 return rawCfg, nil 415 } 416 417 func ParseRawConfig(rawCfg *RawConfig) (config *Config, err error) { 418 defer func() { 419 if err != nil { 420 providerTypes.Cleanup(config.Proxies, config.Providers) 421 config = nil 422 } 423 geodata.CleanGeoSiteCache() 424 runtime.GC() 425 }() 426 427 config = &Config{} 428 429 config.Experimental = &rawCfg.Experimental 430 config.Profile = &rawCfg.Profile 431 432 general, err := parseGeneral(rawCfg) 433 if err != nil { 434 return 435 } 436 config.General = general 437 438 config.Inbounds = rawCfg.Inbounds 439 440 proxies, providers, err := parseProxies(rawCfg) 441 if err != nil { 442 return 443 } 444 config.Proxies = proxies 445 config.Providers = providers 446 447 matchers, rawRules, err := parseScript(rawCfg.Script, rawCfg.Rule) 448 if err != nil { 449 return 450 } 451 rawCfg.Rule = rawRules 452 config.MainMatcher = matchers["main"] 453 454 rules, ruleProviders, err := parseRules(rawCfg, proxies, matchers) 455 if err != nil { 456 return 457 } 458 config.Rules = rules 459 config.RuleProviders = ruleProviders 460 461 hosts, err := parseHosts(rawCfg) 462 if err != nil { 463 return 464 } 465 config.Hosts = hosts 466 467 dnsCfg, err := parseDNS(rawCfg, hosts) 468 if err != nil { 469 return 470 } 471 config.DNS = dnsCfg 472 473 mitmCfg, err := parseMitm(rawCfg.MITM) 474 if err != nil { 475 return 476 } 477 config.Mitm = mitmCfg 478 479 config.Users = ParseAuthentication(rawCfg.Authentication) 480 481 config.Tunnels = rawCfg.Tunnels 482 // verify tunnels 483 for _, t := range config.Tunnels { 484 if _, ok := config.Proxies[t.Proxy]; !ok { 485 pds := config.Providers 486 loop: 487 for _, pd := range pds { 488 if pd.VehicleType() == providerTypes.Compatible { 489 continue 490 } 491 for _, p := range pd.Proxies() { 492 ok = p.Name() == t.Proxy 493 if ok { 494 break loop 495 } 496 } 497 } 498 if !ok { 499 err = fmt.Errorf("tunnel proxy %s not found", t.Proxy) 500 return 501 } 502 } 503 } 504 505 err = verifyScriptMatcher(config, matchers) 506 return 507 } 508 509 func parseGeneral(cfg *RawConfig) (*General, error) { 510 externalUI := cfg.ExternalUI 511 512 // checkout externalUI exist 513 if externalUI != "" { 514 externalUI = C.Path.Resolve(externalUI) 515 516 if _, err := os.Stat(externalUI); os.IsNotExist(err) { 517 return nil, fmt.Errorf("external-ui: %s not exist", externalUI) 518 } 519 } 520 521 cfg.Tun.RedirectToTun = cfg.EBpf.RedirectToTun 522 523 return &General{ 524 LegacyInbound: LegacyInbound{ 525 Port: cfg.Port, 526 SocksPort: cfg.SocksPort, 527 RedirPort: cfg.RedirPort, 528 TProxyPort: cfg.TProxyPort, 529 MixedPort: cfg.MixedPort, 530 MitmPort: cfg.MitmPort, 531 AllowLan: cfg.AllowLan, 532 BindAddress: cfg.BindAddress, 533 }, 534 Controller: Controller{ 535 ExternalController: cfg.ExternalController, 536 ExternalUI: cfg.ExternalUI, 537 Secret: cfg.Secret, 538 PPROF: cfg.PPROF, 539 }, 540 Mode: cfg.Mode, 541 LogLevel: cfg.LogLevel, 542 IPv6: cfg.IPv6, 543 Interface: cfg.Interface, 544 RoutingMark: cfg.RoutingMark, 545 Sniffing: cfg.Sniffing, 546 Tun: cfg.Tun, 547 EBpf: cfg.EBpf, 548 }, nil 549 } 550 551 func parseProxies(cfg *RawConfig) (proxiesMap map[string]C.Proxy, pdsMap map[string]providerTypes.ProxyProvider, err error) { 552 proxies := make(map[string]C.Proxy) 553 providersMap := make(map[string]providerTypes.ProxyProvider) 554 proxiesConfig := cfg.Proxy 555 groupsConfig := cfg.ProxyGroup 556 providersConfig := cfg.ProxyProvider 557 forceCertVerify := cfg.ForceCertVerify 558 559 var proxyList []string 560 561 proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect()) 562 proxies["REJECT"] = adapter.NewProxy(outbound.NewReject()) 563 proxyList = append(proxyList, "DIRECT", "REJECT") 564 565 defer func() { 566 if err != nil { 567 providerTypes.Cleanup(proxies, providersMap) 568 } 569 }() 570 571 // parse proxy 572 for idx, mapping := range proxiesConfig { 573 mapping.Init() 574 proxy, err := adapter.ParseProxy(mapping.M, adapter.ProxyOption{ForceCertVerify: forceCertVerify}) 575 if err != nil { 576 return nil, nil, fmt.Errorf("proxy %d: %w", idx, err) 577 } 578 579 if _, exist := proxies[proxy.Name()]; exist { 580 return nil, nil, fmt.Errorf("proxy %s is the duplicate name", proxy.Name()) 581 } 582 proxies[proxy.Name()] = proxy 583 proxyList = append(proxyList, proxy.Name()) 584 } 585 586 // keep the original order of ProxyGroups in config file 587 for idx, mapping := range groupsConfig { 588 groupName, existName := mapping["name"].(string) 589 if !existName { 590 return nil, nil, fmt.Errorf("proxy group %d: missing name", idx) 591 } 592 proxyList = append(proxyList, groupName) 593 } 594 595 // check if any loop exists and sort the ProxyGroups 596 if err := proxyGroupsDagSort(groupsConfig); err != nil { 597 return nil, nil, err 598 } 599 600 // parse and initial providers 601 for name, mapping := range providersConfig { 602 if name == provider.ReservedName { 603 return nil, nil, fmt.Errorf( 604 "can not defined a provider called `%s`", provider.ReservedName, 605 ) 606 } 607 608 pd, err := provider.ParseProxyProvider(name, mapping, forceCertVerify) 609 if err != nil { 610 return nil, nil, fmt.Errorf("parse proxy provider %s error: %w", name, err) 611 } 612 613 providersMap[name] = pd 614 } 615 616 for _, proxyProvider := range providersMap { 617 log.Info().Str("name", proxyProvider.Name()).Msg("[Config] initial proxy provider") 618 if err := proxyProvider.Initial(); err != nil { 619 return nil, nil, fmt.Errorf( 620 "initial proxy provider %s error: %w", proxyProvider.Name(), err, 621 ) 622 } 623 } 624 625 // parse proxy group 626 for idx, mapping := range groupsConfig { 627 group, err := outboundgroup.ParseProxyGroup(mapping, proxies, providersMap) 628 if err != nil { 629 return nil, nil, fmt.Errorf("proxy group[%d]: %w", idx, err) 630 } 631 632 groupName := group.Name() 633 if _, exist := proxies[groupName]; exist { 634 return nil, nil, fmt.Errorf("proxy group %s: the duplicate name", groupName) 635 } 636 637 proxies[groupName] = adapter.NewProxy(group) 638 } 639 640 // initial compatible provider 641 for _, pd := range providersMap { 642 if pd.VehicleType() != providerTypes.Compatible { 643 continue 644 } 645 646 log.Info().Str("name", pd.Name()).Msg("[Config] initial compatible provider") 647 if err := pd.Initial(); err != nil { 648 return nil, nil, fmt.Errorf( 649 "initial compatible provider %s error: %w", pd.Name(), err, 650 ) 651 } 652 } 653 654 var ps []C.Proxy 655 for _, v := range proxyList { 656 ps = append(ps, proxies[v]) 657 } 658 hc := provider.NewHealthCheck(ps, "", 0, true) 659 pd, _ := provider.NewCompatibleProvider(provider.ReservedName, hc, nil) 660 pd.SetProxies(ps) 661 providersMap[provider.ReservedName] = pd 662 663 global := outboundgroup.NewSelector( 664 &outboundgroup.GroupCommonOption{ 665 Name: "GLOBAL", 666 }, 667 []providerTypes.ProxyProvider{pd}, 668 ) 669 proxies["GLOBAL"] = adapter.NewProxy(global) 670 return proxies, providersMap, nil 671 } 672 673 func parseRules(cfg *RawConfig, proxies map[string]C.Proxy, matchers map[string]C.Matcher) ([]C.Rule, map[string]C.Rule, error) { 674 defer runtime.GC() 675 676 ruleProviders := make(map[string]C.Rule) 677 678 rules, err := parseRawRules(cfg.Rule, ruleProviders, proxies, matchers) 679 if err != nil { 680 return nil, nil, err 681 } 682 683 return rules, ruleProviders, nil 684 } 685 686 func parseRawRules( 687 rawRules []RawRule, 688 ruleProviders map[string]C.Rule, 689 proxies map[string]C.Proxy, 690 matchers map[string]C.Matcher, 691 ) ([]C.Rule, error) { 692 rules := make([]C.Rule, 0, len(rawRules)) 693 694 for idx, raw := range rawRules { 695 line := raw.Line 696 if line == "" { 697 if raw.Name == "" { 698 continue 699 } 700 701 mk := "rule:" + raw.Name 702 if _, ok := matchers[mk]; ok { 703 return nil, fmt.Errorf("parse rule %s failed, rule name is exist", raw.Name) 704 } 705 706 var ( 707 groupMatcher C.Matcher 708 err error 709 ) 710 711 if raw.Engine == "expr" { 712 groupMatcher, err = S.NewExprMatcher(raw.Name, raw.If) 713 } else { 714 groupMatcher, err = S.NewMatcher(raw.Name, "", raw.If) 715 } 716 717 if err != nil { 718 return nil, fmt.Errorf("parse rule %s failed, %w", raw.Name, err) 719 } 720 721 matchers[mk] = groupMatcher 722 723 subRules, err := parseRawRules(raw.Rules, ruleProviders, proxies, matchers) 724 if err != nil { 725 return nil, err 726 } 727 728 appendRuleGroupName(subRules, raw.Name) 729 730 parsed := R.NewGroup(fmt.Sprintf("%s (%s)", raw.Name, raw.If), groupMatcher, subRules) 731 732 rules = append(rules, parsed) 733 734 rpdArr := findRuleProvidersName(raw.If) 735 for _, v := range rpdArr { 736 v = strings.ToLower(v) 737 if _, ok := ruleProviders[v]; ok { 738 continue 739 } 740 rpd, err := R.NewGEOSITE(v, C.ScriptRuleGeoSiteTarget) 741 if err != nil { 742 continue 743 } 744 ruleProviders[v] = rpd 745 } 746 continue 747 } 748 749 rule := trimArr(strings.Split(line, ",")) 750 var ( 751 payload string 752 target string 753 params []string 754 ruleName = strings.ToUpper(rule[0]) 755 ) 756 757 l := len(rule) 758 759 if l < 2 { 760 return nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line) 761 } 762 763 if l < 4 { 764 rule = append(rule, make([]string, 4-l)...) 765 } 766 767 if ruleName == "MATCH" { 768 l = 2 769 } 770 771 if l >= 3 { 772 l = 3 773 payload = rule[1] 774 } 775 776 target = rule[l-1] 777 params = rule[l:] 778 779 if _, ok := proxies[target]; !ok && ruleName != "GEOSITE" && target != C.ScriptRuleGeoSiteTarget { 780 return nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target) 781 } 782 783 pvName := strings.ToLower(payload) 784 _, foundRP := ruleProviders[pvName] 785 if ruleName == "GEOSITE" && target == C.ScriptRuleGeoSiteTarget && foundRP { 786 continue 787 } 788 789 params = trimArr(params) 790 791 parsed, parseErr := R.ParseRule(ruleName, payload, target, params) 792 if parseErr != nil { 793 return nil, fmt.Errorf("rules[%d] [%s] error: %w", idx, line, parseErr) 794 } 795 796 if scr, ok := parsed.(*R.Script); ok { 797 m := matchers[payload] 798 if m == nil { 799 return nil, fmt.Errorf( 800 "rules[%d] [%s] error: shortcut name [%s] not found", idx, line, payload, 801 ) 802 } 803 scr.SetMatcher(m) 804 } 805 806 if ruleName == "GEOSITE" && !foundRP { 807 ruleProviders[pvName] = parsed 808 } 809 810 rules = append(rules, parsed) 811 } 812 813 return rules, nil 814 } 815 816 func appendRuleGroupName(subRules []C.Rule, groupName string) { 817 for i := range subRules { 818 subRules[i].AppendGroup(groupName) 819 if subRules[i].RuleType() != C.Group { 820 continue 821 } 822 appendRuleGroupName(subRules[i].SubRules(), groupName) 823 } 824 } 825 826 func parseHosts(cfg *RawConfig) (*trie.DomainTrie[netip.Addr], error) { 827 tree := trie.New[netip.Addr]() 828 829 // add default hosts 830 if err := tree.Insert("localhost", netip.AddrFrom4([4]byte{127, 0, 0, 1})); err != nil { 831 log.Error().Err(err).Msg("[Config] insert localhost to host failed") 832 } 833 834 if len(cfg.Hosts) != 0 { 835 for domain, ipStr := range cfg.Hosts { 836 ip, err := netip.ParseAddr(ipStr) 837 if err != nil { 838 return nil, fmt.Errorf("%s is not a valid IP", ipStr) 839 } 840 _ = tree.Insert(domain, ip) 841 } 842 } 843 844 // add mitm.clash hosts 845 if err := tree.Insert("mitm.clash", netip.AddrFrom4([4]byte{1, 2, 3, 4})); err != nil { 846 log.Error().Err(err).Msg("[Config] insert mitm.clash to host failed") 847 } 848 849 return tree, nil 850 } 851 852 func hostWithDefaultPort(host string, defPort string) (string, error) { 853 if !strings.Contains(host, ":") { 854 host += ":" 855 } 856 857 hostname, port, err := net.SplitHostPort(host) 858 if err != nil { 859 return "", err 860 } 861 862 if port == "" { 863 port = defPort 864 } 865 866 return net.JoinHostPort(hostname, port), nil 867 } 868 869 func parseNameServer(servers []string) ([]dns.NameServer, error) { 870 var nameservers []dns.NameServer 871 872 for idx, server := range servers { 873 // parse without scheme .e.g 8.8.8.8:53 874 if !strings.Contains(server, "://") { 875 server = "udp://" + server 876 } 877 u, err := url.Parse(server) 878 if err != nil { 879 return nil, fmt.Errorf("DNS NameServer[%d] format error: %w", idx, err) 880 } 881 882 var addr, dnsNetType string 883 switch u.Scheme { 884 case "udp": 885 addr, err = hostWithDefaultPort(u.Host, "53") 886 dnsNetType = "" // UDP 887 case "tcp": 888 addr, err = hostWithDefaultPort(u.Host, "53") 889 dnsNetType = "tcp" // TCP 890 case "tls": 891 addr, err = hostWithDefaultPort(u.Host, "853") 892 dnsNetType = "tcp-tls" // DNS over TLS 893 case "https": 894 clearURL := url.URL{Scheme: "https", Host: u.Host, Path: u.Path, User: u.User} 895 addr = clearURL.String() 896 dnsNetType = "https" // DNS over HTTPS 897 case "dhcp": 898 addr = u.Host 899 dnsNetType = "dhcp" // UDP from DHCP 900 default: 901 return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme) 902 } 903 904 if err != nil { 905 return nil, fmt.Errorf("DNS NameServer[%d] format error: %w", idx, err) 906 } 907 908 nameservers = append( 909 nameservers, 910 dns.NameServer{ 911 Net: dnsNetType, 912 Addr: addr, 913 Proxy: u.Fragment, 914 }, 915 ) 916 } 917 return nameservers, nil 918 } 919 920 func parseNameServerPolicy(nsPolicy map[string]string) (map[string]dns.NameServer, error) { 921 policy := map[string]dns.NameServer{} 922 923 for domain, server := range nsPolicy { 924 nameservers, err := parseNameServer([]string{server}) 925 if err != nil { 926 return nil, err 927 } 928 if _, valid := trie.ValidAndSplitDomain(domain); !valid { 929 return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain) 930 } 931 policy[domain] = nameservers[0] 932 } 933 934 return policy, nil 935 } 936 937 func parseFallbackIPCIDR(ips []string) ([]*netip.Prefix, error) { 938 var ipNets []*netip.Prefix 939 940 for idx, ip := range ips { 941 ipnet, err := netip.ParsePrefix(ip) 942 if err != nil { 943 return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %w", idx, err) 944 } 945 ipNets = append(ipNets, &ipnet) 946 } 947 948 return ipNets, nil 949 } 950 951 func parseFallbackGeoSite(countries []string) ([]*router.DomainMatcher, error) { 952 var sites []*router.DomainMatcher 953 for _, country := range countries { 954 matcher, recordsCount, err := geodata.LoadProviderByCode(country) 955 if err != nil { 956 return nil, err 957 } 958 959 sites = append(sites, matcher) 960 961 cont := fmt.Sprintf("%d", recordsCount) 962 if recordsCount == 0 { 963 cont = "from cache" 964 } 965 log.Info(). 966 Str("country", country). 967 Str("records", cont). 968 Msg("[Config] initial GeoSite dns fallback filter") 969 } 970 return sites, nil 971 } 972 973 func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[netip.Addr]) (*DNS, error) { 974 cfg := rawCfg.DNS 975 if cfg.Enable && len(cfg.NameServer) == 0 { 976 return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty") 977 } 978 979 dnsCfg := &DNS{ 980 Enable: cfg.Enable, 981 Listen: cfg.Listen, 982 IPv6: lo.FromPtrOr(cfg.IPv6, rawCfg.IPv6), 983 EnhancedMode: cfg.EnhancedMode, 984 RemoteDnsResolve: cfg.RemoteDnsResolve, 985 FallbackFilter: FallbackFilter{ 986 IPCIDR: []*netip.Prefix{}, 987 GeoSite: []*router.DomainMatcher{}, 988 }, 989 } 990 var err error 991 if dnsCfg.NameServer, err = parseNameServer(cfg.NameServer); err != nil { 992 return nil, err 993 } 994 995 if dnsCfg.Fallback, err = parseNameServer(cfg.Fallback); err != nil { 996 return nil, err 997 } 998 999 if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy); err != nil { 1000 return nil, err 1001 } 1002 1003 if dnsCfg.ProxyServerNameserver, err = parseNameServer(cfg.ProxyServerNameserver); err != nil { 1004 return nil, err 1005 } 1006 1007 if cfg.RemoteDnsResolve && len(cfg.RemoteNameserver) == 0 { 1008 return nil, errors.New( 1009 "remote nameserver should have at least one nameserver when `remote-dns-resolve` is enable", 1010 ) 1011 } 1012 if dnsCfg.RemoteNameserver, err = parseNameServer(cfg.RemoteNameserver); err != nil { 1013 return nil, err 1014 } 1015 // check remote nameserver should not include any dhcp client 1016 for _, ns := range dnsCfg.RemoteNameserver { 1017 if ns.Net == "dhcp" { 1018 return nil, errors.New("remote nameserver should not contain any dhcp client") 1019 } 1020 } 1021 1022 if len(cfg.DefaultNameserver) == 0 { 1023 return nil, errors.New("default nameserver should have at least one nameserver") 1024 } 1025 if dnsCfg.DefaultNameserver, err = parseNameServer(cfg.DefaultNameserver); err != nil { 1026 return nil, err 1027 } 1028 // check default nameserver is pure ip addr 1029 for _, ns := range dnsCfg.DefaultNameserver { 1030 host, _, err := net.SplitHostPort(ns.Addr) 1031 if err != nil || net.ParseIP(host) == nil { 1032 return nil, errors.New("default nameserver should be pure IP") 1033 } 1034 } 1035 1036 if cfg.EnhancedMode == C.DNSFakeIP { 1037 ipnet, err := netip.ParsePrefix(cfg.FakeIPRange) 1038 if err != nil { 1039 return nil, err 1040 } 1041 1042 defaultFakeIPFilter := []string{ 1043 "*.lan", 1044 "*.local", 1045 "*.localhost", 1046 "*.test", 1047 "+.msftconnecttest.com", 1048 "localhost.ptlogin2.qq.com", 1049 "localhost.sec.qq.com", 1050 } 1051 1052 // add all nameserver host to fake ip skip host filter 1053 defaultFakeIPFilter = append(defaultFakeIPFilter, 1054 lo.Filter( 1055 lo.Map( 1056 append(dnsCfg.NameServer, 1057 append(dnsCfg.Fallback, 1058 append(dnsCfg.ProxyServerNameserver, dnsCfg.RemoteNameserver...)...)...), 1059 func(ns dns.NameServer, _ int) string { 1060 h, _, _ := net.SplitHostPort(ns.Addr) 1061 if _, err := netip.ParseAddr(h); err != nil { 1062 return h 1063 } 1064 return "" 1065 }), 1066 func(s string, _ int) bool { 1067 return s != "" 1068 }, 1069 )..., 1070 ) 1071 1072 // add policy to fake ip skip host filter 1073 if len(dnsCfg.NameServerPolicy) != 0 { 1074 for key, policy := range dnsCfg.NameServerPolicy { 1075 h, _, _ := net.SplitHostPort(policy.Addr) 1076 1077 if a, err := netip.ParseAddr(h); err != nil { 1078 defaultFakeIPFilter = append(defaultFakeIPFilter, h) 1079 } else if a.IsLoopback() || a.IsPrivate() { 1080 defaultFakeIPFilter = append(defaultFakeIPFilter, key) 1081 } 1082 } 1083 } 1084 1085 host := trie.New[bool]() 1086 1087 // fake ip skip host filter 1088 fakeIPFilter := lo.Uniq(append(cfg.FakeIPFilter, defaultFakeIPFilter...)) 1089 for _, domain := range fakeIPFilter { 1090 _ = host.Insert(domain, true) 1091 } 1092 1093 resolver.StoreFakePoolState() 1094 1095 pool, err := fakeip.New(fakeip.Options{ 1096 IPNet: &ipnet, 1097 Size: 1000, 1098 Host: host, 1099 Persistence: rawCfg.Profile.StoreFakeIP, 1100 }) 1101 if err != nil { 1102 return nil, err 1103 } 1104 1105 dnsCfg.FakeIPRange = pool 1106 } 1107 1108 if len(cfg.Fallback) != 0 { 1109 dnsCfg.FallbackFilter.GeoIP = cfg.FallbackFilter.GeoIP 1110 dnsCfg.FallbackFilter.GeoIPCode = cfg.FallbackFilter.GeoIPCode 1111 if fallbackip, err := parseFallbackIPCIDR(cfg.FallbackFilter.IPCIDR); err == nil { 1112 dnsCfg.FallbackFilter.IPCIDR = fallbackip 1113 } 1114 dnsCfg.FallbackFilter.Domain = cfg.FallbackFilter.Domain 1115 fallbackGeoSite, err := parseFallbackGeoSite(cfg.FallbackFilter.GeoSite) 1116 if err != nil { 1117 return nil, fmt.Errorf("load GeoSite dns fallback filter error, %w", err) 1118 } 1119 dnsCfg.FallbackFilter.GeoSite = fallbackGeoSite 1120 } 1121 1122 if cfg.UseHosts { 1123 dnsCfg.Hosts = hosts 1124 } 1125 1126 if len(cfg.SearchDomains) != 0 { 1127 for _, domain := range cfg.SearchDomains { 1128 if strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") { 1129 return nil, errors.New("search domains should not start or end with '.'") 1130 } 1131 if strings.Contains(domain, ":") { 1132 return nil, errors.New("search domains are for ipv4 only and should not contain ports") 1133 } 1134 } 1135 dnsCfg.SearchDomains = cfg.SearchDomains 1136 } 1137 1138 return dnsCfg, nil 1139 } 1140 1141 func ParseAuthentication(rawRecords []string) []auth.AuthUser { 1142 var users []auth.AuthUser 1143 for _, line := range rawRecords { 1144 if user, pass, found := strings.Cut(line, ":"); found { 1145 users = append(users, auth.AuthUser{User: user, Pass: pass}) 1146 } 1147 } 1148 return users 1149 } 1150 1151 func parseScript(script Script, rawRules []RawRule) (map[string]C.Matcher, []RawRule, error) { 1152 var ( 1153 engine = script.Engine 1154 path = script.MainPath 1155 mainCode = script.MainCode 1156 shortcutsCode = script.ShortcutsCode 1157 ) 1158 1159 if len(shortcutsCode) > 0 && engine != "expr" && engine != "starlark" { 1160 return nil, nil, fmt.Errorf("invalid script shortcut engine, got %s, want expr or starlark", engine) 1161 } 1162 1163 if path != "" { 1164 if !strings.HasSuffix(path, ".star") { 1165 return nil, nil, fmt.Errorf("initialized script file failure, script path [%s] invalid", path) 1166 } 1167 path = C.Path.Resolve(path) 1168 if _, err := os.Stat(path); os.IsNotExist(err) { 1169 return nil, nil, fmt.Errorf("initialized script file failure, script path invalid: %w", err) 1170 } 1171 data, err := os.ReadFile(path) 1172 if err != nil { 1173 return nil, nil, fmt.Errorf("initialized script file failure, read file error: %w", err) 1174 } 1175 mainCode = string(data) 1176 } 1177 1178 if strings.TrimSpace(mainCode) == "" { 1179 mainCode = ` 1180 def main(ctx, metadata): 1181 return "DIRECT" 1182 ` 1183 } else { 1184 mainCode = cleanScriptKeywords(mainCode) 1185 } 1186 1187 content := mainCode + "\n" 1188 1189 matcher, err := S.NewMatcher("main", "", mainCode) 1190 if err != nil { 1191 return nil, nil, fmt.Errorf("initialized script module failure, %w", err) 1192 } 1193 1194 matchers := make(map[string]C.Matcher) 1195 matchers["main"] = matcher 1196 for k, v := range shortcutsCode { 1197 if _, ok := matchers[k]; ok { 1198 return nil, nil, fmt.Errorf("initialized rule SCRIPT failure, shortcut name [%s] is exist", k) 1199 } 1200 1201 v = strings.TrimSpace(v) 1202 if v == "" { 1203 return nil, nil, fmt.Errorf("initialized rule SCRIPT failure, shortcut [%s] code syntax invalid", k) 1204 } 1205 1206 v = strings.ReplaceAll(strings.ReplaceAll(v, "\r", " "), "\n", " ") 1207 1208 var m C.Matcher 1209 if engine == "expr" { 1210 m, err = S.NewExprMatcher(k, v) 1211 } else { 1212 m, err = S.NewMatcher(k, "", v) 1213 } 1214 if err != nil { 1215 return nil, nil, fmt.Errorf("initialized script module failure, %w", err) 1216 } 1217 1218 matchers[k] = m 1219 content += v + "\n" 1220 } 1221 1222 rpdArr := findRuleProvidersName(content) 1223 for _, v := range rpdArr { 1224 rule := fmt.Sprintf("GEOSITE,%s,%s", v, C.ScriptRuleGeoSiteTarget) 1225 rawRules = append(rawRules, RawRule(rawRule{Line: rule})) 1226 } 1227 1228 log.Info().Str("engine", engine).Msg("[Config] initial script module successful") 1229 1230 return matchers, rawRules, nil 1231 } 1232 1233 func cleanScriptKeywords(code string) string { 1234 keywords := []string{ 1235 `load\(`, `def resolve_ip\(`, `def in_cidr\(`, `def in_ipset\(`, `def geoip\(`, `def log\(`, 1236 `def match_provider\(`, `def resolve_process_name\(`, `def resolve_process_path\(`, 1237 } 1238 1239 for _, kw := range keywords { 1240 reg := regexp.MustCompile("(?m)[\r\n]+^.*" + kw + ".*$") 1241 code = reg.ReplaceAllString(code, "") 1242 } 1243 return code 1244 } 1245 1246 func findRuleProvidersName(s string) []string { 1247 var ( 1248 regxStr = `ctx.rule_providers\[["'](\S+)["']\]\.match|match_provider\(["'](\S+)["']\)` 1249 regx = regexp.MustCompile(regxStr) 1250 arr = regx.FindAllStringSubmatch(s, -1) 1251 rpd []string 1252 ) 1253 1254 for _, rpdArr := range arr { 1255 for i, v := range rpdArr { 1256 if i == 0 || v == "" { 1257 continue 1258 } 1259 rpd = append(rpd, v) 1260 } 1261 } 1262 1263 return lo.Uniq(rpd) 1264 } 1265 1266 func parseMitm(rawMitm RawMitm) (*Mitm, error) { 1267 var ( 1268 req []C.Rewrite 1269 res []C.Rewrite 1270 ) 1271 1272 for _, line := range rawMitm.Rules { 1273 rule, err := mitm.ParseRewrite(line) 1274 if err != nil { 1275 return nil, fmt.Errorf("parse rewrite rule failure: %w", err) 1276 } 1277 1278 if rule.RuleType() == C.MitmResponseHeader || rule.RuleType() == C.MitmResponseBody { 1279 res = append(res, rule) 1280 } else { 1281 req = append(req, rule) 1282 } 1283 } 1284 1285 hosts := trie.New[bool]() 1286 1287 if len(rawMitm.Hosts) != 0 { 1288 for _, domain := range rawMitm.Hosts { 1289 _ = hosts.Insert(domain, true) 1290 } 1291 } 1292 1293 _ = hosts.Insert("mitm.clash", true) 1294 1295 return &Mitm{ 1296 Hosts: hosts, 1297 Rules: mitm.NewRewriteRules(req, res), 1298 }, nil 1299 } 1300 1301 func verifyScriptMatcher(config *Config, matchers map[string]C.Matcher) (err error) { 1302 defer func() { 1303 if r := recover(); r != nil { 1304 err = fmt.Errorf("test script code panic: %v", r) 1305 } 1306 }() 1307 1308 if len(matchers) == 0 { 1309 return 1310 } 1311 1312 metadata := &C.Metadata{ 1313 Type: C.SOCKS5, 1314 NetWork: C.TCP, 1315 Host: "www.example.com", 1316 SrcIP: netip.MustParseAddr("198.18.0.8"), 1317 SrcPort: 12345, 1318 DstPort: 443, 1319 } 1320 1321 metadata1 := &C.Metadata{ 1322 Type: C.TUN, 1323 NetWork: C.UDP, 1324 Host: "8.8.8.8", 1325 SrcIP: netip.MustParseAddr("192.168.1.123"), 1326 SrcPort: 6789, 1327 DstPort: 2023, 1328 } 1329 1330 cases := []*C.Metadata{metadata, metadata1} 1331 1332 C.BackupScriptState() 1333 1334 C.GetScriptProxyProviders = func() map[string][]C.Proxy { 1335 providersMap := make(map[string][]C.Proxy) 1336 for k, v := range config.Providers { 1337 providersMap[k] = v.Proxies() 1338 } 1339 return providersMap 1340 } 1341 1342 C.SetScriptRuleProviders(config.RuleProviders) 1343 defer C.RestoreScriptState() 1344 1345 for k, v := range matchers { 1346 isMain := k == "main" 1347 for i := range cases { 1348 if isMain { 1349 _, err = v.Eval(cases[i]) 1350 } else { 1351 _, err = v.Match(cases[i]) 1352 } 1353 if err != nil { 1354 err = fmt.Errorf("verify script code failed: %w", err) 1355 return 1356 } 1357 } 1358 } 1359 1360 return 1361 }