clash/config/config.go

1015 lines
28 KiB
Go
Raw Normal View History

package config
import (
2021-11-16 12:08:52 +00:00
"container/list"
"errors"
"fmt"
2022-04-23 01:36:11 +00:00
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
2018-12-05 13:13:29 +00:00
"net"
"net/netip"
2018-12-05 13:13:29 +00:00
"net/url"
"os"
2021-11-17 08:03:47 +00:00
"runtime"
"strconv"
"strings"
2022-02-04 18:42:49 +00:00
"time"
"github.com/Dreamacro/clash/common/utils"
R "github.com/Dreamacro/clash/rule"
RP "github.com/Dreamacro/clash/rule/provider"
2021-06-10 06:05:56 +00:00
"github.com/Dreamacro/clash/adapter"
"github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/adapter/outboundgroup"
"github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/component/auth"
2022-03-08 21:08:35 +00:00
"github.com/Dreamacro/clash/component/dialer"
2019-05-02 16:05:14 +00:00
"github.com/Dreamacro/clash/component/fakeip"
2021-11-17 08:03:47 +00:00
"github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/geodata/router"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
providerTypes "github.com/Dreamacro/clash/constant/provider"
2018-12-05 13:13:29 +00:00
"github.com/Dreamacro/clash/dns"
2018-11-21 05:47:46 +00:00
"github.com/Dreamacro/clash/log"
T "github.com/Dreamacro/clash/tunnel"
2022-03-17 04:26:43 +00:00
"gopkg.in/yaml.v2"
)
2018-08-11 18:23:46 +00:00
// General config
type General struct {
2020-06-18 10:11:02 +00:00
Inbound
Controller
2022-02-04 16:51:06 +00:00
Mode T.TunnelMode `json:"mode"`
UnifiedDelay bool
LogLevel log.LogLevel `json:"log-level"`
IPv6 bool `json:"ipv6"`
Interface string `json:"-"`
2022-03-15 16:43:08 +00:00
RoutingMark int `json:"-"`
GeodataMode bool `json:"geodata-mode"`
2022-02-04 16:51:06 +00:00
GeodataLoader string `json:"geodata-loader"`
TCPConcurrent bool `json:"tcp-concurrent"`
2020-06-18 10:11:02 +00:00
}
2022-03-14 18:55:06 +00:00
// Inbound config
2020-06-18 10:11:02 +00:00
type Inbound struct {
Port int `json:"port"`
SocksPort int `json:"socks-port"`
RedirPort int `json:"redir-port"`
TProxyPort int `json:"tproxy-port"`
2020-06-18 10:11:02 +00:00
MixedPort int `json:"mixed-port"`
Authentication []string `json:"authentication"`
AllowLan bool `json:"allow-lan"`
BindAddress string `json:"bind-address"`
}
2022-03-14 18:55:06 +00:00
// Controller config
2020-06-18 10:11:02 +00:00
type Controller struct {
ExternalController string `json:"-"`
ExternalUI string `json:"-"`
Secret string `json:"-"`
2018-08-11 18:23:46 +00:00
}
2018-12-05 13:13:29 +00:00
// DNS config
type DNS struct {
2022-03-27 16:44:13 +00:00
Enable bool `yaml:"enable"`
IPv6 bool `yaml:"ipv6"`
NameServer []dns.NameServer `yaml:"nameserver"`
Fallback []dns.NameServer `yaml:"fallback"`
FallbackFilter FallbackFilter `yaml:"fallback-filter"`
Listen string `yaml:"listen"`
EnhancedMode C.DNSMode `yaml:"enhanced-mode"`
DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
FakeIPRange *fakeip.Pool
2022-04-10 22:28:42 +00:00
Hosts *trie.DomainTrie[netip.Addr]
2022-03-27 16:44:13 +00:00
NameServerPolicy map[string]dns.NameServer
ProxyServerNameserver []dns.NameServer
2019-09-15 05:36:45 +00:00
}
// FallbackFilter config
type FallbackFilter struct {
2021-11-17 08:03:47 +00:00
GeoIP bool `yaml:"geoip"`
GeoIPCode string `yaml:"geoip-code"`
2022-04-19 17:52:51 +00:00
IPCIDR []*netip.Prefix `yaml:"ipcidr"`
2021-11-17 08:03:47 +00:00
Domain []string `yaml:"domain"`
GeoSite []*router.DomainMatcher `yaml:"geosite"`
}
2021-11-16 12:08:52 +00:00
var (
GroupsList = list.New()
ProxiesList = list.New()
ParsingProxiesCallback func(groupsList *list.List, proxiesList *list.List)
)
// Profile config
type Profile struct {
StoreSelected bool `yaml:"store-selected"`
StoreFakeIP bool `yaml:"store-fake-ip"`
}
2021-11-17 08:03:47 +00:00
// Tun config
type Tun struct {
Enable bool `yaml:"enable" json:"enable"`
Device string `yaml:"device" json:"device"`
Stack C.TUNStack `yaml:"stack" json:"stack"`
DNSHijack []netip.AddrPort `yaml:"dns-hijack" json:"dns-hijack"`
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
2021-11-17 08:03:47 +00:00
}
// IPTables config
type IPTables struct {
2022-03-23 03:04:43 +00:00
Enable bool `yaml:"enable" json:"enable"`
InboundInterface string `yaml:"inbound-interface" json:"inbound-interface"`
Bypass []string `yaml:"bypass" json:"bypass"`
}
type Sniffer struct {
Enable bool
Force bool
Sniffers []C.SnifferType
Reverses *trie.DomainTrie[bool]
ForceDomain *trie.DomainTrie[bool]
SkipSNI *trie.DomainTrie[bool]
Ports *[]utils.Range[uint16]
}
// Experimental config
type Experimental struct{}
// Config is clash config manager
type Config struct {
2021-11-17 08:03:47 +00:00
General *General
Tun *Tun
2022-03-23 02:18:08 +00:00
IPTables *IPTables
2021-11-17 08:03:47 +00:00
DNS *DNS
Experimental *Experimental
2022-04-10 22:28:42 +00:00
Hosts *trie.DomainTrie[netip.Addr]
2021-11-17 08:03:47 +00:00
Profile *Profile
Rules []C.Rule
Users []auth.AuthUser
Proxies map[string]C.Proxy
Providers map[string]providerTypes.ProxyProvider
2021-12-02 14:56:17 +00:00
RuleProviders map[string]*providerTypes.RuleProvider
Sniffer *Sniffer
}
2020-01-10 16:22:34 +00:00
type RawDNS struct {
2022-03-27 16:44:13 +00:00
Enable bool `yaml:"enable"`
IPv6 bool `yaml:"ipv6"`
UseHosts bool `yaml:"use-hosts"`
NameServer []string `yaml:"nameserver"`
Fallback []string `yaml:"fallback"`
FallbackFilter RawFallbackFilter `yaml:"fallback-filter"`
Listen string `yaml:"listen"`
EnhancedMode C.DNSMode `yaml:"enhanced-mode"`
FakeIPRange string `yaml:"fake-ip-range"`
FakeIPFilter []string `yaml:"fake-ip-filter"`
DefaultNameserver []string `yaml:"default-nameserver"`
NameServerPolicy map[string]string `yaml:"nameserver-policy"`
ProxyServerNameserver []string `yaml:"proxy-server-nameserver"`
2019-09-15 05:36:45 +00:00
}
2020-01-10 16:22:34 +00:00
type RawFallbackFilter struct {
2021-08-25 07:15:13 +00:00
GeoIP bool `yaml:"geoip"`
GeoIPCode string `yaml:"geoip-code"`
IPCIDR []string `yaml:"ipcidr"`
Domain []string `yaml:"domain"`
2021-11-17 08:03:47 +00:00
GeoSite []string `yaml:"geosite"`
2018-12-05 13:13:29 +00:00
}
2022-03-08 21:08:35 +00:00
type RawTun struct {
Enable bool `yaml:"enable" json:"enable"`
Device string `yaml:"device" json:"device"`
Stack C.TUNStack `yaml:"stack" json:"stack"`
DNSHijack []string `yaml:"dns-hijack" json:"dns-hijack"`
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
AutoDetectInterface bool `yaml:"auto-detect-interface"`
2022-03-08 21:08:35 +00:00
}
2020-01-10 16:22:34 +00:00
type RawConfig struct {
2018-12-05 13:13:29 +00:00
Port int `yaml:"port"`
SocksPort int `yaml:"socks-port"`
RedirPort int `yaml:"redir-port"`
TProxyPort int `yaml:"tproxy-port"`
MixedPort int `yaml:"mixed-port"`
Authentication []string `yaml:"authentication"`
2018-12-05 13:13:29 +00:00
AllowLan bool `yaml:"allow-lan"`
BindAddress string `yaml:"bind-address"`
Mode T.TunnelMode `yaml:"mode"`
UnifiedDelay bool `yaml:"unified-delay"`
2018-12-05 13:13:29 +00:00
LogLevel log.LogLevel `yaml:"log-level"`
2020-06-18 10:11:02 +00:00
IPv6 bool `yaml:"ipv6"`
2018-12-05 13:13:29 +00:00
ExternalController string `yaml:"external-controller"`
2018-12-19 17:29:13 +00:00
ExternalUI string `yaml:"external-ui"`
2018-12-05 13:13:29 +00:00
Secret string `yaml:"secret"`
Interface string `yaml:"interface-name"`
2022-03-15 16:43:08 +00:00
RoutingMark int `yaml:"routing-mark"`
GeodataMode bool `yaml:"geodata-mode"`
2022-02-04 16:51:06 +00:00
GeodataLoader string `yaml:"geodata-loader"`
2022-04-22 16:45:43 +00:00
TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"`
2018-12-05 13:13:29 +00:00
Sniffer SnifferRaw `yaml:"sniffer"`
2022-03-16 04:10:13 +00:00
ProxyProvider map[string]map[string]any `yaml:"proxy-providers"`
Merge remote-tracking branch 'yaling888/with-tun' into Alpha # Conflicts: # .github/workflows/codeql-analysis.yml # .github/workflows/linter.yml # .github/workflows/release.yml # Makefile # README.md # adapter/outbound/vless.go # component/geodata/memconservative/cache.go # component/geodata/router/condition.go # component/geodata/router/condition_geoip.go # component/geodata/standard/standard.go # component/geodata/utils.go # config/config.go # config/initial.go # constant/metadata.go # constant/path.go # constant/rule.go # constant/rule_extra.go # dns/client.go # dns/filters.go # dns/resolver.go # go.mod # go.sum # hub/executor/executor.go # hub/route/configs.go # listener/listener.go # listener/tproxy/tproxy_linux_iptables.go # listener/tun/dev/dev.go # listener/tun/dev/dev_darwin.go # listener/tun/dev/dev_linux.go # listener/tun/dev/dev_windows.go # listener/tun/dev/wintun/config.go # listener/tun/dev/wintun/dll_windows.go # listener/tun/dev/wintun/session_windows.go # listener/tun/dev/wintun/wintun_windows.go # listener/tun/ipstack/commons/dns.go # listener/tun/ipstack/gvisor/tun.go # listener/tun/ipstack/gvisor/tundns.go # listener/tun/ipstack/gvisor/utils.go # listener/tun/ipstack/stack_adapter.go # listener/tun/ipstack/system/dns.go # listener/tun/ipstack/system/tcp.go # listener/tun/ipstack/system/tun.go # listener/tun/tun_adapter.go # main.go # rule/common/base.go # rule/common/domain.go # rule/common/domain_keyword.go # rule/common/domain_suffix.go # rule/common/final.go # rule/common/geoip.go # rule/common/geosite.go # rule/common/ipcidr.go # rule/common/port.go # rule/parser.go # rule/process.go # test/go.mod # test/go.sum # transport/vless/xtls.go # tunnel/tunnel.go
2022-03-17 09:41:02 +00:00
RuleProvider map[string]map[string]any `yaml:"rule-providers"`
2022-03-16 04:10:13 +00:00
Hosts map[string]string `yaml:"hosts"`
DNS RawDNS `yaml:"dns"`
Tun RawTun `yaml:"tun"`
IPTables IPTables `yaml:"iptables"`
2022-03-16 04:10:13 +00:00
Experimental Experimental `yaml:"experimental"`
Profile Profile `yaml:"profile"`
Proxy []map[string]any `yaml:"proxies"`
ProxyGroup []map[string]any `yaml:"proxy-groups"`
Rule []string `yaml:"rules"`
2018-12-05 13:13:29 +00:00
}
type SnifferRaw struct {
Enable bool `yaml:"enable" json:"enable"`
Sniffing []string `yaml:"sniffing" json:"sniffing"`
Force bool `yaml:"force" json:"force"`
Reverse []string `yaml:"reverses" json:"reverses"`
ForceDomain []string `yaml:"force-domain" json:"force-domain"`
SkipSNI []string `yaml:"skip-sni" json:"skip-sni"`
Ports []string `yaml:"port-whitelist" json:"port-whitelist"`
}
// Parse config
func Parse(buf []byte) (*Config, error) {
2020-01-10 16:22:34 +00:00
rawCfg, err := UnmarshalRawConfig(buf)
if err != nil {
return nil, err
}
return ParseRawConfig(rawCfg)
}
2018-10-14 13:22:58 +00:00
2020-01-10 16:22:34 +00:00
func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
// config with default value
2020-01-10 16:22:34 +00:00
rawCfg := &RawConfig{
AllowLan: false,
BindAddress: "*",
Mode: T.Rule,
2022-03-16 09:29:09 +00:00
GeodataMode: C.GeodataMode,
2022-02-04 16:51:06 +00:00
GeodataLoader: "memconservative",
UnifiedDelay: false,
Authentication: []string{},
LogLevel: log.INFO,
2019-09-11 09:00:55 +00:00
Hosts: map[string]string{},
Rule: []string{},
2022-03-16 04:10:13 +00:00
Proxy: []map[string]any{},
ProxyGroup: []map[string]any{},
TCPConcurrent: false,
Merge remote-tracking branch 'yaling888/with-tun' into Alpha # Conflicts: # .github/workflows/codeql-analysis.yml # .github/workflows/linter.yml # .github/workflows/release.yml # Makefile # README.md # adapter/outbound/vless.go # component/geodata/memconservative/cache.go # component/geodata/router/condition.go # component/geodata/router/condition_geoip.go # component/geodata/standard/standard.go # component/geodata/utils.go # config/config.go # config/initial.go # constant/metadata.go # constant/path.go # constant/rule.go # constant/rule_extra.go # dns/client.go # dns/filters.go # dns/resolver.go # go.mod # go.sum # hub/executor/executor.go # hub/route/configs.go # listener/listener.go # listener/tproxy/tproxy_linux_iptables.go # listener/tun/dev/dev.go # listener/tun/dev/dev_darwin.go # listener/tun/dev/dev_linux.go # listener/tun/dev/dev_windows.go # listener/tun/dev/wintun/config.go # listener/tun/dev/wintun/dll_windows.go # listener/tun/dev/wintun/session_windows.go # listener/tun/dev/wintun/wintun_windows.go # listener/tun/ipstack/commons/dns.go # listener/tun/ipstack/gvisor/tun.go # listener/tun/ipstack/gvisor/tundns.go # listener/tun/ipstack/gvisor/utils.go # listener/tun/ipstack/stack_adapter.go # listener/tun/ipstack/system/dns.go # listener/tun/ipstack/system/tcp.go # listener/tun/ipstack/system/tun.go # listener/tun/tun_adapter.go # main.go # rule/common/base.go # rule/common/domain.go # rule/common/domain_keyword.go # rule/common/domain_suffix.go # rule/common/final.go # rule/common/geoip.go # rule/common/geosite.go # rule/common/ipcidr.go # rule/common/port.go # rule/parser.go # rule/process.go # test/go.mod # test/go.sum # transport/vless/xtls.go # tunnel/tunnel.go
2022-03-17 09:41:02 +00:00
Tun: RawTun{
Enable: false,
Device: "",
AutoDetectInterface: true,
Stack: C.TunGvisor,
DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query
AutoRoute: true,
Merge remote-tracking branch 'yaling888/with-tun' into Alpha # Conflicts: # .github/workflows/codeql-analysis.yml # .github/workflows/linter.yml # .github/workflows/release.yml # Makefile # README.md # adapter/outbound/vless.go # component/geodata/memconservative/cache.go # component/geodata/router/condition.go # component/geodata/router/condition_geoip.go # component/geodata/standard/standard.go # component/geodata/utils.go # config/config.go # config/initial.go # constant/metadata.go # constant/path.go # constant/rule.go # constant/rule_extra.go # dns/client.go # dns/filters.go # dns/resolver.go # go.mod # go.sum # hub/executor/executor.go # hub/route/configs.go # listener/listener.go # listener/tproxy/tproxy_linux_iptables.go # listener/tun/dev/dev.go # listener/tun/dev/dev_darwin.go # listener/tun/dev/dev_linux.go # listener/tun/dev/dev_windows.go # listener/tun/dev/wintun/config.go # listener/tun/dev/wintun/dll_windows.go # listener/tun/dev/wintun/session_windows.go # listener/tun/dev/wintun/wintun_windows.go # listener/tun/ipstack/commons/dns.go # listener/tun/ipstack/gvisor/tun.go # listener/tun/ipstack/gvisor/tundns.go # listener/tun/ipstack/gvisor/utils.go # listener/tun/ipstack/stack_adapter.go # listener/tun/ipstack/system/dns.go # listener/tun/ipstack/system/tcp.go # listener/tun/ipstack/system/tun.go # listener/tun/tun_adapter.go # main.go # rule/common/base.go # rule/common/domain.go # rule/common/domain_keyword.go # rule/common/domain_suffix.go # rule/common/final.go # rule/common/geoip.go # rule/common/geosite.go # rule/common/ipcidr.go # rule/common/port.go # rule/parser.go # rule/process.go # test/go.mod # test/go.sum # transport/vless/xtls.go # tunnel/tunnel.go
2022-03-17 09:41:02 +00:00
},
IPTables: IPTables{
Enable: false,
InboundInterface: "lo",
2022-03-23 03:04:43 +00:00
Bypass: []string{},
},
2020-01-10 16:22:34 +00:00
DNS: RawDNS{
2022-03-08 21:08:35 +00:00
Enable: false,
UseHosts: true,
EnhancedMode: C.DNSMapping,
FakeIPRange: "198.18.0.1/16",
2020-01-10 16:22:34 +00:00
FallbackFilter: RawFallbackFilter{
2021-08-25 07:15:13 +00:00
GeoIP: true,
GeoIPCode: "CN",
IPCIDR: []string{},
2021-11-17 08:03:47 +00:00
GeoSite: []string{},
2019-09-15 05:36:45 +00:00
},
DefaultNameserver: []string{
"114.114.114.114",
2021-11-17 08:03:47 +00:00
"223.5.5.5",
"8.8.8.8",
"1.0.0.1",
},
NameServer: []string{
2022-03-08 21:08:35 +00:00
"https://doh.pub/dns-query",
"tls://223.5.5.5:853",
},
FakeIPFilter: []string{
"dns.msftnsci.com",
"www.msftnsci.com",
"www.msftconnecttest.com",
},
2018-12-05 13:52:31 +00:00
},
Sniffer: SnifferRaw{
Enable: false,
Force: false,
Sniffing: []string{},
Reverse: []string{},
ForceDomain: []string{},
SkipSNI: []string{},
Ports: []string{},
},
Profile: Profile{
StoreSelected: true,
},
}
2020-01-10 16:22:34 +00:00
if err := yaml.Unmarshal(buf, rawCfg); err != nil {
2018-11-21 05:47:46 +00:00
return nil, err
}
2020-01-10 16:22:34 +00:00
return rawCfg, nil
}
func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
config := &Config{}
2022-02-05 17:59:35 +00:00
log.Infoln("Start initial configuration in progress") //Segment finished in xxm
startTime := time.Now()
config.Experimental = &rawCfg.Experimental
config.Profile = &rawCfg.Profile
config.IPTables = &rawCfg.IPTables
2018-11-21 05:47:46 +00:00
general, err := parseGeneral(rawCfg)
if err != nil {
return nil, err
}
2018-11-21 05:47:46 +00:00
config.General = general
2022-03-08 21:08:35 +00:00
tunCfg, err := parseTun(rawCfg.Tun, config.General)
if err != nil {
return nil, err
}
config.Tun = tunCfg
dialer.DefaultInterface.Store(config.General.Interface)
2019-12-08 04:17:24 +00:00
proxies, providers, err := parseProxies(rawCfg)
2018-11-21 05:47:46 +00:00
if err != nil {
return nil, err
}
2018-11-21 05:47:46 +00:00
config.Proxies = proxies
2019-12-08 04:17:24 +00:00
config.Providers = providers
2021-11-17 08:03:47 +00:00
rules, ruleProviders, err := parseRules(rawCfg, proxies)
if err != nil {
2018-11-21 05:47:46 +00:00
return nil, err
}
2018-11-21 05:47:46 +00:00
config.Rules = rules
2021-11-17 08:03:47 +00:00
config.RuleProviders = ruleProviders
hosts, err := parseHosts(rawCfg)
2018-12-05 13:13:29 +00:00
if err != nil {
return nil, err
}
config.Hosts = hosts
2018-12-05 13:13:29 +00:00
2021-11-17 08:03:47 +00:00
dnsCfg, err := parseDNS(rawCfg, hosts, rules)
2019-09-11 09:00:55 +00:00
if err != nil {
return nil, err
}
config.DNS = dnsCfg
2019-09-11 09:00:55 +00:00
config.Users = parseAuthentication(rawCfg.Authentication)
2020-01-10 16:22:34 +00:00
config.Sniffer, err = parseSniffer(rawCfg.Sniffer)
if err != nil {
return nil, err
}
2022-02-05 17:59:35 +00:00
elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms
log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) //Segment finished in xxm
2018-11-21 05:47:46 +00:00
return config, nil
}
2020-01-10 16:22:34 +00:00
func parseGeneral(cfg *RawConfig) (*General, error) {
2018-12-19 17:29:13 +00:00
externalUI := cfg.ExternalUI
2022-02-04 18:42:49 +00:00
geodata.SetLoader(cfg.GeodataLoader)
2020-06-18 10:11:02 +00:00
// checkout externalUI exist
2018-12-21 02:55:21 +00:00
if externalUI != "" {
2020-01-30 09:03:11 +00:00
externalUI = C.Path.Resolve(externalUI)
2018-12-21 02:55:21 +00:00
if _, err := os.Stat(externalUI); os.IsNotExist(err) {
return nil, fmt.Errorf("external-ui: %s not exist", externalUI)
}
2018-12-19 17:29:13 +00:00
}
2020-06-18 10:11:02 +00:00
return &General{
Inbound: Inbound{
Port: cfg.Port,
SocksPort: cfg.SocksPort,
RedirPort: cfg.RedirPort,
TProxyPort: cfg.TProxyPort,
2020-06-18 10:11:02 +00:00
MixedPort: cfg.MixedPort,
AllowLan: cfg.AllowLan,
BindAddress: cfg.BindAddress,
},
Controller: Controller{
ExternalController: cfg.ExternalController,
ExternalUI: cfg.ExternalUI,
Secret: cfg.Secret,
},
2022-02-04 18:42:49 +00:00
UnifiedDelay: cfg.UnifiedDelay,
Mode: cfg.Mode,
LogLevel: cfg.LogLevel,
IPv6: cfg.IPv6,
Interface: cfg.Interface,
2022-03-15 16:43:08 +00:00
RoutingMark: cfg.RoutingMark,
GeodataMode: cfg.GeodataMode,
2022-02-04 18:42:49 +00:00
GeodataLoader: cfg.GeodataLoader,
TCPConcurrent: cfg.TCPConcurrent,
2020-06-18 10:11:02 +00:00
}, nil
}
func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]providerTypes.ProxyProvider, err error) {
2019-12-08 04:17:24 +00:00
proxies = make(map[string]C.Proxy)
providersMap = make(map[string]providerTypes.ProxyProvider)
proxiesConfig := cfg.Proxy
groupsConfig := cfg.ProxyGroup
2019-12-08 04:17:24 +00:00
providersConfig := cfg.ProxyProvider
2022-03-14 18:55:06 +00:00
var proxyList []string
Merge remote-tracking branch 'yaling888/with-tun' into Alpha # Conflicts: # .github/workflows/codeql-analysis.yml # .github/workflows/linter.yml # .github/workflows/release.yml # Makefile # README.md # adapter/outbound/vless.go # component/geodata/memconservative/cache.go # component/geodata/router/condition.go # component/geodata/router/condition_geoip.go # component/geodata/standard/standard.go # component/geodata/utils.go # config/config.go # config/initial.go # constant/metadata.go # constant/path.go # constant/rule.go # constant/rule_extra.go # dns/client.go # dns/filters.go # dns/resolver.go # go.mod # go.sum # hub/executor/executor.go # hub/route/configs.go # listener/listener.go # listener/tproxy/tproxy_linux_iptables.go # listener/tun/dev/dev.go # listener/tun/dev/dev_darwin.go # listener/tun/dev/dev_linux.go # listener/tun/dev/dev_windows.go # listener/tun/dev/wintun/config.go # listener/tun/dev/wintun/dll_windows.go # listener/tun/dev/wintun/session_windows.go # listener/tun/dev/wintun/wintun_windows.go # listener/tun/ipstack/commons/dns.go # listener/tun/ipstack/gvisor/tun.go # listener/tun/ipstack/gvisor/tundns.go # listener/tun/ipstack/gvisor/utils.go # listener/tun/ipstack/stack_adapter.go # listener/tun/ipstack/system/dns.go # listener/tun/ipstack/system/tcp.go # listener/tun/ipstack/system/tun.go # listener/tun/tun_adapter.go # main.go # rule/common/base.go # rule/common/domain.go # rule/common/domain_keyword.go # rule/common/domain_suffix.go # rule/common/final.go # rule/common/geoip.go # rule/common/geosite.go # rule/common/ipcidr.go # rule/common/port.go # rule/parser.go # rule/process.go # test/go.mod # test/go.sum # transport/vless/xtls.go # tunnel/tunnel.go
2022-03-17 09:41:02 +00:00
_proxiesList := list.New()
_groupsList := list.New()
2022-03-14 18:55:06 +00:00
2021-06-10 06:05:56 +00:00
proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect())
proxies["REJECT"] = adapter.NewProxy(outbound.NewReject())
proxies["COMPATIBLE"] = adapter.NewProxy(outbound.NewCompatible())
proxies["PASS"] = adapter.NewProxy(outbound.NewPass())
proxyList = append(proxyList, "DIRECT", "REJECT")
// parse proxy
for idx, mapping := range proxiesConfig {
2021-06-10 06:05:56 +00:00
proxy, err := adapter.ParseProxy(mapping)
if err != nil {
2020-08-25 14:19:59 +00:00
return nil, nil, fmt.Errorf("proxy %d: %w", idx, err)
2018-10-27 04:57:56 +00:00
}
if _, exist := proxies[proxy.Name()]; exist {
2020-08-25 14:19:59 +00:00
return nil, nil, fmt.Errorf("proxy %s is the duplicate name", proxy.Name())
}
2019-12-08 04:17:24 +00:00
proxies[proxy.Name()] = proxy
proxyList = append(proxyList, proxy.Name())
2021-11-16 12:08:52 +00:00
_proxiesList.PushBack(mapping)
}
2020-04-08 07:49:12 +00:00
// keep the original order of ProxyGroups in config file
for idx, mapping := range groupsConfig {
groupName, existName := mapping["name"].(string)
if !existName {
2020-08-25 14:19:59 +00:00
return nil, nil, fmt.Errorf("proxy group %d: missing name", idx)
}
proxyList = append(proxyList, groupName)
2021-11-16 12:08:52 +00:00
_groupsList.PushBack(mapping)
}
// check if any loop exists and sort the ProxyGroups
2019-12-08 04:17:24 +00:00
if err := proxyGroupsDagSort(groupsConfig); err != nil {
return nil, nil, err
}
2019-12-08 04:17:24 +00:00
// parse and initial providers
for name, mapping := range providersConfig {
if name == provider.ReservedName {
return nil, nil, fmt.Errorf("can not defined a provider called `%s`", provider.ReservedName)
}
2019-12-08 04:17:24 +00:00
pd, err := provider.ParseProxyProvider(name, mapping)
if err != nil {
2020-05-31 16:39:41 +00:00
return nil, nil, fmt.Errorf("parse proxy provider %s error: %w", name, err)
}
2019-12-08 04:17:24 +00:00
providersMap[name] = pd
}
2019-02-15 06:25:20 +00:00
2019-12-08 04:17:24 +00:00
// parse proxy group
for idx, mapping := range groupsConfig {
group, err := outboundgroup.ParseProxyGroup(mapping, proxies, providersMap)
if err != nil {
2020-08-25 14:19:59 +00:00
return nil, nil, fmt.Errorf("proxy group[%d]: %w", idx, err)
}
2019-12-08 04:17:24 +00:00
groupName := group.Name()
if _, exist := proxies[groupName]; exist {
2020-08-25 14:19:59 +00:00
return nil, nil, fmt.Errorf("proxy group %s: the duplicate name", groupName)
2019-12-08 04:17:24 +00:00
}
2021-06-10 06:05:56 +00:00
proxies[groupName] = adapter.NewProxy(group)
}
2022-03-14 18:55:06 +00:00
var ps []C.Proxy
for _, v := range proxyList {
if proxies[v].Type() == C.Pass {
continue
}
ps = append(ps, proxies[v])
}
hc := provider.NewHealthCheck(ps, "", 0, true)
2020-01-11 13:02:55 +00:00
pd, _ := provider.NewCompatibleProvider(provider.ReservedName, ps, hc)
2019-12-08 04:17:24 +00:00
providersMap[provider.ReservedName] = pd
global := outboundgroup.NewSelector(
&outboundgroup.GroupCommonOption{
Name: "GLOBAL",
},
[]providerTypes.ProxyProvider{pd},
)
2021-06-10 06:05:56 +00:00
proxies["GLOBAL"] = adapter.NewProxy(global)
2021-11-16 12:08:52 +00:00
ProxiesList = _proxiesList
GroupsList = _groupsList
if ParsingProxiesCallback != nil {
// refresh tray menu
go ParsingProxiesCallback(GroupsList, ProxiesList)
}
2019-12-08 04:17:24 +00:00
return proxies, providersMap, nil
}
2021-12-02 14:56:17 +00:00
func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[string]*providerTypes.RuleProvider, error) {
ruleProviders := map[string]*providerTypes.RuleProvider{}
2022-02-05 17:59:35 +00:00
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
2021-12-02 14:56:17 +00:00
// parse rule provider
for name, mapping := range cfg.RuleProvider {
rp, err := RP.ParseRuleProvider(name, mapping)
2021-12-02 14:56:17 +00:00
if err != nil {
return nil, nil, err
}
ruleProviders[name] = &rp
RP.SetRuleProvider(rp)
2021-12-02 14:56:17 +00:00
}
var rules []C.Rule
rulesConfig := cfg.Rule
2021-11-17 08:03:47 +00:00
mode := cfg.Mode
// parse rules
for idx, line := range rulesConfig {
rule := trimArr(strings.Split(line, ","))
var (
2021-11-17 08:03:47 +00:00
payload string
target string
params []string
2021-11-17 08:03:47 +00:00
ruleName = strings.ToUpper(rule[0])
)
2021-11-17 08:03:47 +00:00
if mode == T.Script && ruleName != "GEOSITE" {
continue
}
Merge remote-tracking branch 'yaling888/with-tun' into Alpha # Conflicts: # .github/workflows/codeql-analysis.yml # .github/workflows/linter.yml # .github/workflows/release.yml # Makefile # README.md # adapter/outbound/vless.go # component/geodata/memconservative/cache.go # component/geodata/router/condition.go # component/geodata/router/condition_geoip.go # component/geodata/standard/standard.go # component/geodata/utils.go # config/config.go # config/initial.go # constant/metadata.go # constant/path.go # constant/rule.go # constant/rule_extra.go # dns/client.go # dns/filters.go # dns/resolver.go # go.mod # go.sum # hub/executor/executor.go # hub/route/configs.go # listener/listener.go # listener/tproxy/tproxy_linux_iptables.go # listener/tun/dev/dev.go # listener/tun/dev/dev_darwin.go # listener/tun/dev/dev_linux.go # listener/tun/dev/dev_windows.go # listener/tun/dev/wintun/config.go # listener/tun/dev/wintun/dll_windows.go # listener/tun/dev/wintun/session_windows.go # listener/tun/dev/wintun/wintun_windows.go # listener/tun/ipstack/commons/dns.go # listener/tun/ipstack/gvisor/tun.go # listener/tun/ipstack/gvisor/tundns.go # listener/tun/ipstack/gvisor/utils.go # listener/tun/ipstack/stack_adapter.go # listener/tun/ipstack/system/dns.go # listener/tun/ipstack/system/tcp.go # listener/tun/ipstack/system/tun.go # listener/tun/tun_adapter.go # main.go # rule/common/base.go # rule/common/domain.go # rule/common/domain_keyword.go # rule/common/domain_suffix.go # rule/common/final.go # rule/common/geoip.go # rule/common/geosite.go # rule/common/ipcidr.go # rule/common/port.go # rule/parser.go # rule/process.go # test/go.mod # test/go.sum # transport/vless/xtls.go # tunnel/tunnel.go
2022-03-17 09:41:02 +00:00
l := len(rule)
2022-03-14 18:55:06 +00:00
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" {
Merge remote-tracking branch 'yaling888/with-tun' into Alpha # Conflicts: # .github/workflows/codeql-analysis.yml # .github/workflows/linter.yml # .github/workflows/release.yml # Makefile # README.md # adapter/outbound/vless.go # component/geodata/memconservative/cache.go # component/geodata/router/condition.go # component/geodata/router/condition_geoip.go # component/geodata/standard/standard.go # component/geodata/utils.go # config/config.go # config/initial.go # constant/metadata.go # constant/path.go # constant/rule.go # constant/rule_extra.go # dns/client.go # dns/filters.go # dns/resolver.go # go.mod # go.sum # hub/executor/executor.go # hub/route/configs.go # listener/listener.go # listener/tproxy/tproxy_linux_iptables.go # listener/tun/dev/dev.go # listener/tun/dev/dev_darwin.go # listener/tun/dev/dev_linux.go # listener/tun/dev/dev_windows.go # listener/tun/dev/wintun/config.go # listener/tun/dev/wintun/dll_windows.go # listener/tun/dev/wintun/session_windows.go # listener/tun/dev/wintun/wintun_windows.go # listener/tun/ipstack/commons/dns.go # listener/tun/ipstack/gvisor/tun.go # listener/tun/ipstack/gvisor/tundns.go # listener/tun/ipstack/gvisor/utils.go # listener/tun/ipstack/stack_adapter.go # listener/tun/ipstack/system/dns.go # listener/tun/ipstack/system/tcp.go # listener/tun/ipstack/system/tun.go # listener/tun/tun_adapter.go # main.go # rule/common/base.go # rule/common/domain.go # rule/common/domain_keyword.go # rule/common/domain_suffix.go # rule/common/final.go # rule/common/geoip.go # rule/common/geosite.go # rule/common/ipcidr.go # rule/common/port.go # rule/parser.go # rule/process.go # test/go.mod # test/go.sum # transport/vless/xtls.go # tunnel/tunnel.go
2022-03-17 09:41:02 +00:00
target = rule[l-1]
payload = strings.Join(rule[1:l-1], ",")
} else {
Merge remote-tracking branch 'yaling888/with-tun' into Alpha # Conflicts: # .github/workflows/codeql-analysis.yml # .github/workflows/linter.yml # .github/workflows/release.yml # Makefile # README.md # adapter/outbound/vless.go # component/geodata/memconservative/cache.go # component/geodata/router/condition.go # component/geodata/router/condition_geoip.go # component/geodata/standard/standard.go # component/geodata/utils.go # config/config.go # config/initial.go # constant/metadata.go # constant/path.go # constant/rule.go # constant/rule_extra.go # dns/client.go # dns/filters.go # dns/resolver.go # go.mod # go.sum # hub/executor/executor.go # hub/route/configs.go # listener/listener.go # listener/tproxy/tproxy_linux_iptables.go # listener/tun/dev/dev.go # listener/tun/dev/dev_darwin.go # listener/tun/dev/dev_linux.go # listener/tun/dev/dev_windows.go # listener/tun/dev/wintun/config.go # listener/tun/dev/wintun/dll_windows.go # listener/tun/dev/wintun/session_windows.go # listener/tun/dev/wintun/wintun_windows.go # listener/tun/ipstack/commons/dns.go # listener/tun/ipstack/gvisor/tun.go # listener/tun/ipstack/gvisor/tundns.go # listener/tun/ipstack/gvisor/utils.go # listener/tun/ipstack/stack_adapter.go # listener/tun/ipstack/system/dns.go # listener/tun/ipstack/system/tcp.go # listener/tun/ipstack/system/tun.go # listener/tun/tun_adapter.go # main.go # rule/common/base.go # rule/common/domain.go # rule/common/domain_keyword.go # rule/common/domain_suffix.go # rule/common/final.go # rule/common/geoip.go # rule/common/geosite.go # rule/common/ipcidr.go # rule/common/port.go # rule/parser.go # rule/process.go # test/go.mod # test/go.sum # transport/vless/xtls.go # tunnel/tunnel.go
2022-03-17 09:41:02 +00:00
if l < 2 {
2022-03-17 15:24:07 +00:00
return nil, nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
Merge remote-tracking branch 'yaling888/with-tun' into Alpha # Conflicts: # .github/workflows/codeql-analysis.yml # .github/workflows/linter.yml # .github/workflows/release.yml # Makefile # README.md # adapter/outbound/vless.go # component/geodata/memconservative/cache.go # component/geodata/router/condition.go # component/geodata/router/condition_geoip.go # component/geodata/standard/standard.go # component/geodata/utils.go # config/config.go # config/initial.go # constant/metadata.go # constant/path.go # constant/rule.go # constant/rule_extra.go # dns/client.go # dns/filters.go # dns/resolver.go # go.mod # go.sum # hub/executor/executor.go # hub/route/configs.go # listener/listener.go # listener/tproxy/tproxy_linux_iptables.go # listener/tun/dev/dev.go # listener/tun/dev/dev_darwin.go # listener/tun/dev/dev_linux.go # listener/tun/dev/dev_windows.go # listener/tun/dev/wintun/config.go # listener/tun/dev/wintun/dll_windows.go # listener/tun/dev/wintun/session_windows.go # listener/tun/dev/wintun/wintun_windows.go # listener/tun/ipstack/commons/dns.go # listener/tun/ipstack/gvisor/tun.go # listener/tun/ipstack/gvisor/tundns.go # listener/tun/ipstack/gvisor/utils.go # listener/tun/ipstack/stack_adapter.go # listener/tun/ipstack/system/dns.go # listener/tun/ipstack/system/tcp.go # listener/tun/ipstack/system/tun.go # listener/tun/tun_adapter.go # main.go # rule/common/base.go # rule/common/domain.go # rule/common/domain_keyword.go # rule/common/domain_suffix.go # rule/common/final.go # rule/common/geoip.go # rule/common/geosite.go # rule/common/ipcidr.go # rule/common/port.go # rule/parser.go # rule/process.go # test/go.mod # test/go.sum # transport/vless/xtls.go # tunnel/tunnel.go
2022-03-17 09:41:02 +00:00
}
if l < 4 {
rule = append(rule, make([]string, 4-l)...)
}
if ruleName == "MATCH" {
l = 2
}
if l >= 3 {
l = 3
payload = rule[1]
Merge remote-tracking branch 'yaling888/with-tun' into Alpha # Conflicts: # .github/workflows/codeql-analysis.yml # .github/workflows/linter.yml # .github/workflows/release.yml # Makefile # README.md # adapter/outbound/vless.go # component/geodata/memconservative/cache.go # component/geodata/router/condition.go # component/geodata/router/condition_geoip.go # component/geodata/standard/standard.go # component/geodata/utils.go # config/config.go # config/initial.go # constant/metadata.go # constant/path.go # constant/rule.go # constant/rule_extra.go # dns/client.go # dns/filters.go # dns/resolver.go # go.mod # go.sum # hub/executor/executor.go # hub/route/configs.go # listener/listener.go # listener/tproxy/tproxy_linux_iptables.go # listener/tun/dev/dev.go # listener/tun/dev/dev_darwin.go # listener/tun/dev/dev_linux.go # listener/tun/dev/dev_windows.go # listener/tun/dev/wintun/config.go # listener/tun/dev/wintun/dll_windows.go # listener/tun/dev/wintun/session_windows.go # listener/tun/dev/wintun/wintun_windows.go # listener/tun/ipstack/commons/dns.go # listener/tun/ipstack/gvisor/tun.go # listener/tun/ipstack/gvisor/tundns.go # listener/tun/ipstack/gvisor/utils.go # listener/tun/ipstack/stack_adapter.go # listener/tun/ipstack/system/dns.go # listener/tun/ipstack/system/tcp.go # listener/tun/ipstack/system/tun.go # listener/tun/tun_adapter.go # main.go # rule/common/base.go # rule/common/domain.go # rule/common/domain_keyword.go # rule/common/domain_suffix.go # rule/common/final.go # rule/common/geoip.go # rule/common/geosite.go # rule/common/ipcidr.go # rule/common/port.go # rule/parser.go # rule/process.go # test/go.mod # test/go.sum # transport/vless/xtls.go # tunnel/tunnel.go
2022-03-17 09:41:02 +00:00
}
target = rule[l-1]
params = rule[l:]
}
2022-04-10 22:28:42 +00:00
if _, ok := proxies[target]; !ok {
2021-11-17 08:03:47 +00:00
return nil, nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target)
}
params = trimArr(params)
2019-03-30 06:11:59 +00:00
2022-01-23 10:27:44 +00:00
if ruleName == "GEOSITE" {
2022-02-05 20:41:34 +00:00
if err := initGeoSite(); err != nil {
2022-03-17 17:25:59 +00:00
return nil, nil, fmt.Errorf("can't initial GeoSite: %s", err)
2022-01-23 10:27:44 +00:00
}
2022-03-16 14:55:18 +00:00
initMode = false
2022-01-23 10:27:44 +00:00
}
2021-11-17 08:03:47 +00:00
parsed, parseErr := R.ParseRule(ruleName, payload, target, params)
if parseErr != nil {
2021-11-17 08:03:47 +00:00
return nil, nil, fmt.Errorf("rules[%d] [%s] error: %s", idx, line, parseErr.Error())
}
2022-04-10 22:28:42 +00:00
rules = append(rules, parsed)
2021-11-17 08:03:47 +00:00
}
2022-02-05 17:59:35 +00:00
2021-11-17 08:03:47 +00:00
runtime.GC()
2019-03-30 06:11:59 +00:00
2021-11-17 08:03:47 +00:00
return rules, ruleProviders, nil
}
2018-12-05 13:13:29 +00:00
2022-04-10 22:28:42 +00:00
func parseHosts(cfg *RawConfig) (*trie.DomainTrie[netip.Addr], error) {
tree := trie.New[netip.Addr]()
2020-06-07 09:25:51 +00:00
// add default hosts
2022-04-10 22:28:42 +00:00
if err := tree.Insert("localhost", netip.AddrFrom4([4]byte{127, 0, 0, 1})); err != nil {
2020-09-20 07:53:27 +00:00
log.Errorln("insert localhost to host error: %s", err.Error())
2020-06-07 09:25:51 +00:00
}
2019-09-11 09:00:55 +00:00
if len(cfg.Hosts) != 0 {
for domain, ipStr := range cfg.Hosts {
2022-04-10 22:28:42 +00:00
ip, err := netip.ParseAddr(ipStr)
if err != nil {
2019-09-11 09:00:55 +00:00
return nil, fmt.Errorf("%s is not a valid IP", ipStr)
}
2022-03-14 18:55:06 +00:00
_ = tree.Insert(domain, ip)
2019-09-11 09:00:55 +00:00
}
}
return tree, nil
}
2020-02-17 14:13:15 +00:00
func hostWithDefaultPort(host string, defPort string) (string, error) {
2018-12-05 13:13:29 +00:00
if !strings.Contains(host, ":") {
host += ":"
}
hostname, port, err := net.SplitHostPort(host)
if err != nil {
2020-02-17 14:13:15 +00:00
return "", err
2018-12-05 13:13:29 +00:00
}
if port == "" {
port = defPort
}
2020-02-17 14:13:15 +00:00
return net.JoinHostPort(hostname, port), nil
2018-12-05 13:13:29 +00:00
}
func parseNameServer(servers []string) ([]dns.NameServer, error) {
2022-03-14 18:55:06 +00:00
var nameservers []dns.NameServer
2018-12-05 13:13:29 +00:00
for idx, server := range servers {
// parse without scheme .e.g 8.8.8.8:53
if !strings.Contains(server, "://") {
server = "udp://" + server
2018-12-05 13:13:29 +00:00
}
u, err := url.Parse(server)
if err != nil {
return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error())
}
2020-02-17 14:13:15 +00:00
var addr, dnsNetType string
switch u.Scheme {
case "udp":
2020-02-17 14:13:15 +00:00
addr, err = hostWithDefaultPort(u.Host, "53")
dnsNetType = "" // UDP
case "tcp":
2020-02-17 14:13:15 +00:00
addr, err = hostWithDefaultPort(u.Host, "53")
dnsNetType = "tcp" // TCP
case "tls":
2020-02-17 14:13:15 +00:00
addr, err = hostWithDefaultPort(u.Host, "853")
dnsNetType = "tcp-tls" // DNS over TLS
2019-06-28 04:29:08 +00:00
case "https":
clearURL := url.URL{Scheme: "https", Host: u.Host, Path: u.Path}
addr = clearURL.String()
2019-06-28 04:29:08 +00:00
dnsNetType = "https" // DNS over HTTPS
case "dhcp":
addr = u.Host
dnsNetType = "dhcp" // UDP from DHCP
case "quic":
addr, err = hostWithDefaultPort(u.Host, "784")
dnsNetType = "quic" // DNS over QUIC
default:
2018-12-05 13:13:29 +00:00
return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme)
}
2019-06-28 04:29:08 +00:00
if err != nil {
return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error())
}
2018-12-05 13:13:29 +00:00
nameservers = append(
nameservers,
dns.NameServer{
2021-11-17 08:03:47 +00:00
Net: dnsNetType,
Addr: addr,
ProxyAdapter: u.Fragment,
Interface: dialer.DefaultInterface.Load(),
2018-12-05 13:13:29 +00:00
},
)
}
return nameservers, nil
}
func parseNameServerPolicy(nsPolicy map[string]string) (map[string]dns.NameServer, error) {
policy := map[string]dns.NameServer{}
for domain, server := range nsPolicy {
nameservers, err := parseNameServer([]string{server})
if err != nil {
return nil, err
}
if _, valid := trie.ValidAndSplitDomain(domain); !valid {
return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain)
}
policy[domain] = nameservers[0]
}
return policy, nil
}
2022-04-19 17:52:51 +00:00
func parseFallbackIPCIDR(ips []string) ([]*netip.Prefix, error) {
var ipNets []*netip.Prefix
2019-09-15 05:36:45 +00:00
for idx, ip := range ips {
2022-04-19 17:52:51 +00:00
ipnet, err := netip.ParsePrefix(ip)
2019-09-15 05:36:45 +00:00
if err != nil {
return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %s", idx, err.Error())
}
2022-04-19 17:52:51 +00:00
ipNets = append(ipNets, &ipnet)
2019-09-15 05:36:45 +00:00
}
return ipNets, nil
}
2021-11-17 08:03:47 +00:00
func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainMatcher, error) {
var sites []*router.DomainMatcher
2022-01-11 14:17:24 +00:00
if len(countries) > 0 {
2022-02-05 20:41:34 +00:00
if err := initGeoSite(); err != nil {
2022-03-17 17:25:59 +00:00
return nil, fmt.Errorf("can't initial GeoSite: %s", err)
2022-01-11 14:17:24 +00:00
}
}
2021-11-17 08:03:47 +00:00
for _, country := range countries {
found := false
for _, rule := range rules {
if rule.RuleType() == C.GEOSITE {
if strings.EqualFold(country, rule.Payload()) {
found = true
sites = append(sites, rule.(C.RuleGeoSite).GetDomainMatcher())
log.Infoln("Start initial GeoSite dns fallback filter from rule `%s`", country)
}
}
}
if !found {
matcher, recordsCount, err := geodata.LoadGeoSiteMatcher(country)
if err != nil {
return nil, err
}
sites = append(sites, matcher)
log.Infoln("Start initial GeoSite dns fallback filter `%s`, records: %d", country, recordsCount)
}
}
runtime.GC()
return sites, nil
}
2022-04-10 22:28:42 +00:00
func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[netip.Addr], rules []C.Rule) (*DNS, error) {
2021-10-11 12:48:58 +00:00
cfg := rawCfg.DNS
2018-12-05 13:13:29 +00:00
if cfg.Enable && len(cfg.NameServer) == 0 {
2020-08-25 14:19:59 +00:00
return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty")
2018-12-05 13:13:29 +00:00
}
dnsCfg := &DNS{
Enable: cfg.Enable,
Listen: cfg.Listen,
IPv6: cfg.IPv6,
2018-12-05 13:13:29 +00:00
EnhancedMode: cfg.EnhancedMode,
2019-09-15 05:36:45 +00:00
FallbackFilter: FallbackFilter{
2022-04-19 17:52:51 +00:00
IPCIDR: []*netip.Prefix{},
2021-11-17 08:03:47 +00:00
GeoSite: []*router.DomainMatcher{},
2019-09-15 05:36:45 +00:00
},
2018-12-05 13:13:29 +00:00
}
var err error
if dnsCfg.NameServer, err = parseNameServer(cfg.NameServer); err != nil {
return nil, err
2018-12-05 13:13:29 +00:00
}
if dnsCfg.Fallback, err = parseNameServer(cfg.Fallback); err != nil {
return nil, err
2018-12-05 13:13:29 +00:00
}
if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy); err != nil {
return nil, err
}
2022-03-27 16:44:13 +00:00
if dnsCfg.ProxyServerNameserver, err = parseNameServer(cfg.ProxyServerNameserver); err != nil {
return nil, err
}
if len(cfg.DefaultNameserver) == 0 {
return nil, errors.New("default nameserver should have at least one nameserver")
}
if dnsCfg.DefaultNameserver, err = parseNameServer(cfg.DefaultNameserver); err != nil {
return nil, err
}
// check default nameserver is pure ip addr
for _, ns := range dnsCfg.DefaultNameserver {
2020-02-17 14:13:15 +00:00
host, _, err := net.SplitHostPort(ns.Addr)
if err != nil || net.ParseIP(host) == nil {
u, err := url.Parse(ns.Addr)
if err != nil || net.ParseIP(u.Host) == nil {
return nil, errors.New("default nameserver should be pure IP")
}
}
}
if cfg.EnhancedMode == C.DNSFakeIP {
ipnet, err := netip.ParsePrefix(cfg.FakeIPRange)
2019-05-02 16:05:14 +00:00
if err != nil {
return nil, err
}
2019-12-27 16:10:06 +00:00
2022-04-10 22:28:42 +00:00
var host *trie.DomainTrie[bool]
2019-12-27 16:10:06 +00:00
// fake ip skip host filter
if len(cfg.FakeIPFilter) != 0 {
2022-04-10 22:28:42 +00:00
host = trie.New[bool]()
2019-12-27 16:10:06 +00:00
for _, domain := range cfg.FakeIPFilter {
2022-03-14 18:55:06 +00:00
_ = host.Insert(domain, true)
2021-11-17 08:03:47 +00:00
}
}
if len(dnsCfg.Fallback) != 0 {
if host == nil {
2022-04-10 22:28:42 +00:00
host = trie.New[bool]()
2021-11-17 08:03:47 +00:00
}
for _, fb := range dnsCfg.Fallback {
if net.ParseIP(fb.Addr) != nil {
continue
}
_ = host.Insert(fb.Addr, true)
2019-12-27 16:10:06 +00:00
}
}
2021-10-11 12:48:58 +00:00
pool, err := fakeip.New(fakeip.Options{
IPNet: &ipnet,
2021-10-11 12:48:58 +00:00
Size: 1000,
Host: host,
Persistence: rawCfg.Profile.StoreFakeIP,
})
2019-05-02 16:05:14 +00:00
if err != nil {
return nil, err
}
dnsCfg.FakeIPRange = pool
}
2021-11-17 08:03:47 +00:00
if len(cfg.Fallback) != 0 {
dnsCfg.FallbackFilter.GeoIP = cfg.FallbackFilter.GeoIP
dnsCfg.FallbackFilter.GeoIPCode = cfg.FallbackFilter.GeoIPCode
if fallbackip, err := parseFallbackIPCIDR(cfg.FallbackFilter.IPCIDR); err == nil {
dnsCfg.FallbackFilter.IPCIDR = fallbackip
}
dnsCfg.FallbackFilter.Domain = cfg.FallbackFilter.Domain
fallbackGeoSite, err := parseFallbackGeoSite(cfg.FallbackFilter.GeoSite, rules)
if err != nil {
return nil, fmt.Errorf("load GeoSite dns fallback filter error, %w", err)
}
dnsCfg.FallbackFilter.GeoSite = fallbackGeoSite
2019-09-15 05:36:45 +00:00
}
if cfg.UseHosts {
dnsCfg.Hosts = hosts
}
2018-12-05 13:13:29 +00:00
return dnsCfg, nil
}
func parseAuthentication(rawRecords []string) []auth.AuthUser {
var users []auth.AuthUser
for _, line := range rawRecords {
2022-03-16 04:10:13 +00:00
if user, pass, found := strings.Cut(line, ":"); found {
users = append(users, auth.AuthUser{User: user, Pass: pass})
}
}
return users
}
2021-11-17 08:03:47 +00:00
2022-03-08 21:08:35 +00:00
func parseTun(rawTun RawTun, general *General) (*Tun, error) {
if rawTun.Enable && rawTun.AutoDetectInterface {
2022-03-08 21:08:35 +00:00
autoDetectInterfaceName, err := commons.GetAutoDetectInterface()
2022-04-20 14:00:05 +00:00
if err != nil {
log.Warnln("Can not find auto detect interface.[%s]", err)
} else {
log.Warnln("Auto detect interface: %s", autoDetectInterfaceName)
2022-03-08 21:08:35 +00:00
}
general.Interface = autoDetectInterfaceName
}
var dnsHijack []netip.AddrPort
2022-03-14 18:55:06 +00:00
for _, d := range rawTun.DNSHijack {
if _, after, ok := strings.Cut(d, "://"); ok {
d = after
2022-03-08 21:08:35 +00:00
}
d = strings.Replace(d, "any", "0.0.0.0", 1)
2022-03-14 18:55:06 +00:00
addrPort, err := netip.ParseAddrPort(d)
if err != nil {
return nil, fmt.Errorf("parse dns-hijack url error: %w", err)
2022-03-08 21:08:35 +00:00
}
dnsHijack = append(dnsHijack, addrPort)
2022-03-08 21:08:35 +00:00
}
return &Tun{
Enable: rawTun.Enable,
Device: rawTun.Device,
Stack: rawTun.Stack,
DNSHijack: dnsHijack,
AutoRoute: rawTun.AutoRoute,
}, nil
}
func parseSniffer(snifferRaw SnifferRaw) (*Sniffer, error) {
sniffer := &Sniffer{
Enable: snifferRaw.Enable,
Force: snifferRaw.Force,
}
2022-04-23 01:36:11 +00:00
var ports []utils.Range[uint16]
if len(snifferRaw.Ports) == 0 {
ports = append(ports, *utils.NewRange[uint16](0, 65535))
} else {
for _, portRange := range snifferRaw.Ports {
portRaws := strings.Split(portRange, "-")
2022-04-23 01:36:11 +00:00
p, err := strconv.ParseUint(portRaws[0], 10, 16)
if err != nil {
return nil, fmt.Errorf("%s format error", portRange)
}
2022-04-23 01:36:11 +00:00
start := uint16(p)
if len(portRaws) > 1 {
p, err = strconv.ParseUint(portRaws[1], 10, 16)
if err != nil {
return nil, fmt.Errorf("%s format error", portRange)
}
end := uint16(p)
ports = append(ports, *utils.NewRange(start, end))
2022-04-23 01:36:11 +00:00
} else {
ports = append(ports, *utils.NewRange(start, start))
}
}
}
sniffer.Ports = &ports
loadSniffer := make(map[C.SnifferType]struct{})
for _, snifferName := range snifferRaw.Sniffing {
find := false
for _, snifferType := range C.SnifferList {
if snifferType.String() == strings.ToUpper(snifferName) {
find = true
loadSniffer[snifferType] = struct{}{}
}
}
if !find {
return nil, fmt.Errorf("not find the sniffer[%s]", snifferName)
}
}
for st := range loadSniffer {
sniffer.Sniffers = append(sniffer.Sniffers, st)
}
sniffer.ForceDomain = trie.New[bool]()
for _, domain := range snifferRaw.ForceDomain {
err := sniffer.ForceDomain.Insert(domain, true)
if err != nil {
return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err)
}
}
sniffer.SkipSNI = trie.New[bool]()
2022-04-17 13:17:21 +00:00
for _, domain := range snifferRaw.SkipSNI {
err := sniffer.SkipSNI.Insert(domain, true)
if err != nil {
return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err)
}
}
// Compatibility, remove it when release
if strings.Contains(C.Version, "alpha") || strings.Contains(C.Version, "develop") || strings.Contains(C.Version, "1.10.0") {
2022-04-17 12:03:53 +00:00
log.Warnln("Sniffer param force and reverses deprecated, will be removed in the release version, see https://github.com/MetaCubeX/Clash.Meta/commit/48a01adb7a4f38974b9d9639f931d0d245aebf28")
if snifferRaw.Force {
// match all domain
sniffer.ForceDomain.Insert("+", true)
for _, domain := range snifferRaw.Reverse {
err := sniffer.SkipSNI.Insert(domain, true)
if err != nil {
return nil, fmt.Errorf("error domian[%s], error:%v", domain, err)
}
}
} else {
for _, domain := range snifferRaw.Reverse {
err := sniffer.ForceDomain.Insert(domain, true)
if err != nil {
return nil, fmt.Errorf("error domian[%s], error:%v", domain, err)
}
}
}
}
return sniffer, nil
}