2018-07-26 00:04:59 +08:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
2021-11-16 20:08:52 +08:00
|
|
|
"container/list"
|
2020-02-15 21:42:46 +08:00
|
|
|
"errors"
|
2018-07-26 00:04:59 +08:00
|
|
|
"fmt"
|
2022-01-22 22:10:45 +08:00
|
|
|
R "github.com/Dreamacro/clash/rule"
|
|
|
|
RP "github.com/Dreamacro/clash/rule/provider"
|
2018-12-05 21:13:29 +08:00
|
|
|
"net"
|
|
|
|
"net/url"
|
2018-07-26 00:04:59 +08:00
|
|
|
"os"
|
2021-11-17 16:03:47 +08:00
|
|
|
"regexp"
|
|
|
|
"runtime"
|
2018-07-26 00:04:59 +08:00
|
|
|
"strings"
|
2022-02-05 02:42:49 +08:00
|
|
|
"time"
|
2018-07-26 00:04:59 +08:00
|
|
|
|
2021-06-10 14:05:56 +08:00
|
|
|
"github.com/Dreamacro/clash/adapter"
|
|
|
|
"github.com/Dreamacro/clash/adapter/outbound"
|
|
|
|
"github.com/Dreamacro/clash/adapter/outboundgroup"
|
|
|
|
"github.com/Dreamacro/clash/adapter/provider"
|
2019-06-27 17:04:25 +08:00
|
|
|
"github.com/Dreamacro/clash/component/auth"
|
2019-05-03 00:05:14 +08:00
|
|
|
"github.com/Dreamacro/clash/component/fakeip"
|
2021-11-17 16:03:47 +08:00
|
|
|
"github.com/Dreamacro/clash/component/geodata"
|
|
|
|
"github.com/Dreamacro/clash/component/geodata/router"
|
2020-05-28 12:13:05 +08:00
|
|
|
"github.com/Dreamacro/clash/component/trie"
|
2018-07-26 00:04:59 +08:00
|
|
|
C "github.com/Dreamacro/clash/constant"
|
2021-07-04 20:32:59 +08:00
|
|
|
providerTypes "github.com/Dreamacro/clash/constant/provider"
|
2018-12-05 21:13:29 +08:00
|
|
|
"github.com/Dreamacro/clash/dns"
|
2018-11-21 13:47:46 +08:00
|
|
|
"github.com/Dreamacro/clash/log"
|
|
|
|
T "github.com/Dreamacro/clash/tunnel"
|
2018-07-26 00:04:59 +08:00
|
|
|
|
2021-09-13 23:43:28 +08:00
|
|
|
"gopkg.in/yaml.v2"
|
2018-07-26 00:04:59 +08:00
|
|
|
)
|
|
|
|
|
2018-08-12 02:23:46 +08:00
|
|
|
// General config
|
|
|
|
type General struct {
|
2020-06-18 18:11:02 +08:00
|
|
|
Inbound
|
|
|
|
Controller
|
2022-02-05 00:51:06 +08:00
|
|
|
Mode T.TunnelMode `json:"mode"`
|
|
|
|
UnifiedDelay bool
|
|
|
|
LogLevel log.LogLevel `json:"log-level"`
|
|
|
|
IPv6 bool `json:"ipv6"`
|
|
|
|
Interface string `json:"-"`
|
|
|
|
GeodataLoader string `json:"geodata-loader"`
|
2020-06-18 18:11:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Inbound
|
|
|
|
type Inbound struct {
|
|
|
|
Port int `json:"port"`
|
|
|
|
SocksPort int `json:"socks-port"`
|
|
|
|
RedirPort int `json:"redir-port"`
|
2020-11-09 10:46:10 +08:00
|
|
|
TProxyPort int `json:"tproxy-port"`
|
2020-06-18 18:11:02 +08:00
|
|
|
MixedPort int `json:"mixed-port"`
|
|
|
|
Authentication []string `json:"authentication"`
|
|
|
|
AllowLan bool `json:"allow-lan"`
|
|
|
|
BindAddress string `json:"bind-address"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Controller
|
|
|
|
type Controller struct {
|
|
|
|
ExternalController string `json:"-"`
|
|
|
|
ExternalUI string `json:"-"`
|
|
|
|
Secret string `json:"-"`
|
2018-08-12 02:23:46 +08:00
|
|
|
}
|
|
|
|
|
2018-12-05 21:13:29 +08:00
|
|
|
// DNS config
|
|
|
|
type DNS struct {
|
2020-02-15 21:42:46 +08: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"`
|
2021-10-18 21:08:27 +08:00
|
|
|
EnhancedMode C.DNSMode `yaml:"enhanced-mode"`
|
2020-02-15 21:42:46 +08:00
|
|
|
DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
|
|
|
|
FakeIPRange *fakeip.Pool
|
2020-08-11 10:28:17 +08:00
|
|
|
Hosts *trie.DomainTrie
|
2021-05-19 11:17:35 +08:00
|
|
|
NameServerPolicy map[string]dns.NameServer
|
2019-09-15 13:36:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// FallbackFilter config
|
|
|
|
type FallbackFilter struct {
|
2021-11-17 16:03:47 +08:00
|
|
|
GeoIP bool `yaml:"geoip"`
|
|
|
|
GeoIPCode string `yaml:"geoip-code"`
|
|
|
|
IPCIDR []*net.IPNet `yaml:"ipcidr"`
|
|
|
|
Domain []string `yaml:"domain"`
|
|
|
|
GeoSite []*router.DomainMatcher `yaml:"geosite"`
|
2018-10-02 15:26:36 +08:00
|
|
|
}
|
|
|
|
|
2021-11-16 20:08:52 +08:00
|
|
|
var (
|
|
|
|
GroupsList = list.New()
|
|
|
|
ProxiesList = list.New()
|
|
|
|
ParsingProxiesCallback func(groupsList *list.List, proxiesList *list.List)
|
|
|
|
)
|
|
|
|
|
2021-02-18 23:41:50 +08:00
|
|
|
// Profile config
|
|
|
|
type Profile struct {
|
|
|
|
StoreSelected bool `yaml:"store-selected"`
|
2021-11-08 20:48:29 +08:00
|
|
|
StoreFakeIP bool `yaml:"store-fake-ip"`
|
2021-02-18 23:41:50 +08:00
|
|
|
}
|
|
|
|
|
2021-11-17 16:03:47 +08:00
|
|
|
// Tun config
|
|
|
|
type Tun struct {
|
2022-01-05 01:56:35 +08:00
|
|
|
Enable bool `yaml:"enable" json:"enable"`
|
|
|
|
Stack string `yaml:"stack" json:"stack"`
|
|
|
|
DnsHijack []string `yaml:"dns-hijack" json:"dns-hijack"`
|
|
|
|
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Script config
|
|
|
|
type Script struct {
|
|
|
|
MainCode string `yaml:"code" json:"code"`
|
|
|
|
ShortcutsCode map[string]string `yaml:"shortcuts" json:"shortcuts"`
|
|
|
|
}
|
|
|
|
|
2019-04-24 12:02:52 +08:00
|
|
|
// Experimental config
|
2020-06-27 14:19:31 +08:00
|
|
|
type Experimental struct{}
|
2019-04-24 12:02:52 +08:00
|
|
|
|
2021-11-26 00:57:33 +08:00
|
|
|
// Config is clash config manager
|
2018-07-26 00:04:59 +08:00
|
|
|
type Config struct {
|
2021-11-17 16:03:47 +08:00
|
|
|
General *General
|
|
|
|
Tun *Tun
|
|
|
|
DNS *DNS
|
|
|
|
Experimental *Experimental
|
|
|
|
Hosts *trie.DomainTrie
|
|
|
|
Profile *Profile
|
|
|
|
Rules []C.Rule
|
|
|
|
Users []auth.AuthUser
|
|
|
|
Proxies map[string]C.Proxy
|
|
|
|
Providers map[string]providerTypes.ProxyProvider
|
2021-12-02 22:56:17 +08:00
|
|
|
RuleProviders map[string]*providerTypes.RuleProvider
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
|
|
|
|
2020-01-11 00:22:34 +08:00
|
|
|
type RawDNS struct {
|
2020-02-15 21:42:46 +08:00
|
|
|
Enable bool `yaml:"enable"`
|
|
|
|
IPv6 bool `yaml:"ipv6"`
|
2020-08-11 10:28:17 +08:00
|
|
|
UseHosts bool `yaml:"use-hosts"`
|
2020-02-15 21:42:46 +08:00
|
|
|
NameServer []string `yaml:"nameserver"`
|
|
|
|
Fallback []string `yaml:"fallback"`
|
|
|
|
FallbackFilter RawFallbackFilter `yaml:"fallback-filter"`
|
|
|
|
Listen string `yaml:"listen"`
|
2021-10-18 21:08:27 +08:00
|
|
|
EnhancedMode C.DNSMode `yaml:"enhanced-mode"`
|
2020-02-15 21:42:46 +08:00
|
|
|
FakeIPRange string `yaml:"fake-ip-range"`
|
|
|
|
FakeIPFilter []string `yaml:"fake-ip-filter"`
|
|
|
|
DefaultNameserver []string `yaml:"default-nameserver"`
|
2021-05-19 11:17:35 +08:00
|
|
|
NameServerPolicy map[string]string `yaml:"nameserver-policy"`
|
2019-09-15 13:36:45 +08:00
|
|
|
}
|
|
|
|
|
2020-01-11 00:22:34 +08:00
|
|
|
type RawFallbackFilter struct {
|
2021-08-25 15:15:13 +08:00
|
|
|
GeoIP bool `yaml:"geoip"`
|
|
|
|
GeoIPCode string `yaml:"geoip-code"`
|
|
|
|
IPCIDR []string `yaml:"ipcidr"`
|
|
|
|
Domain []string `yaml:"domain"`
|
2021-11-17 16:03:47 +08:00
|
|
|
GeoSite []string `yaml:"geosite"`
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
2020-01-11 00:22:34 +08:00
|
|
|
type RawConfig struct {
|
2018-12-05 21:13:29 +08:00
|
|
|
Port int `yaml:"port"`
|
|
|
|
SocksPort int `yaml:"socks-port"`
|
|
|
|
RedirPort int `yaml:"redir-port"`
|
2020-11-09 10:46:10 +08:00
|
|
|
TProxyPort int `yaml:"tproxy-port"`
|
2020-05-12 11:29:53 +08:00
|
|
|
MixedPort int `yaml:"mixed-port"`
|
2019-06-27 17:04:25 +08:00
|
|
|
Authentication []string `yaml:"authentication"`
|
2018-12-05 21:13:29 +08:00
|
|
|
AllowLan bool `yaml:"allow-lan"`
|
2019-08-08 13:45:07 +08:00
|
|
|
BindAddress string `yaml:"bind-address"`
|
2020-02-15 21:42:46 +08:00
|
|
|
Mode T.TunnelMode `yaml:"mode"`
|
2021-12-26 21:20:41 +08:00
|
|
|
UnifiedDelay bool `yaml:"unified-delay"`
|
2018-12-05 21:13:29 +08:00
|
|
|
LogLevel log.LogLevel `yaml:"log-level"`
|
2020-06-18 18:11:02 +08:00
|
|
|
IPv6 bool `yaml:"ipv6"`
|
2018-12-05 21:13:29 +08:00
|
|
|
ExternalController string `yaml:"external-controller"`
|
2018-12-20 01:29:13 +08:00
|
|
|
ExternalUI string `yaml:"external-ui"`
|
2018-12-05 21:13:29 +08:00
|
|
|
Secret string `yaml:"secret"`
|
2020-06-27 14:19:31 +08:00
|
|
|
Interface string `yaml:"interface-name"`
|
2022-02-05 00:51:06 +08:00
|
|
|
GeodataLoader string `yaml:"geodata-loader"`
|
2018-12-05 21:13:29 +08:00
|
|
|
|
2020-03-07 20:01:24 +08:00
|
|
|
ProxyProvider map[string]map[string]interface{} `yaml:"proxy-providers"`
|
2021-11-25 21:52:07 +08:00
|
|
|
RuleProvider map[string]map[string]interface{} `yaml:"rule-providers"`
|
2019-12-08 12:17:24 +08:00
|
|
|
Hosts map[string]string `yaml:"hosts"`
|
2020-01-11 00:22:34 +08:00
|
|
|
DNS RawDNS `yaml:"dns"`
|
2021-11-17 16:03:47 +08:00
|
|
|
Tun Tun `yaml:"tun"`
|
2019-12-08 12:17:24 +08:00
|
|
|
Experimental Experimental `yaml:"experimental"`
|
2021-02-18 23:41:50 +08:00
|
|
|
Profile Profile `yaml:"profile"`
|
2020-03-07 20:01:24 +08:00
|
|
|
Proxy []map[string]interface{} `yaml:"proxies"`
|
|
|
|
ProxyGroup []map[string]interface{} `yaml:"proxy-groups"`
|
|
|
|
Rule []string `yaml:"rules"`
|
2021-11-17 16:03:47 +08:00
|
|
|
Script Script `yaml:"script"`
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
2019-12-01 13:22:47 +08:00
|
|
|
// Parse config
|
|
|
|
func Parse(buf []byte) (*Config, error) {
|
2020-01-11 00:22:34 +08:00
|
|
|
rawCfg, err := UnmarshalRawConfig(buf)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ParseRawConfig(rawCfg)
|
|
|
|
}
|
2018-10-14 21:22:58 +08:00
|
|
|
|
2020-01-11 00:22:34 +08:00
|
|
|
func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
|
2021-02-18 23:41:50 +08:00
|
|
|
// config with default value
|
2020-01-11 00:22:34 +08:00
|
|
|
rawCfg := &RawConfig{
|
2019-06-27 17:04:25 +08:00
|
|
|
AllowLan: false,
|
2019-08-08 13:45:07 +08:00
|
|
|
BindAddress: "*",
|
2019-06-27 17:04:25 +08:00
|
|
|
Mode: T.Rule,
|
2022-02-05 00:51:06 +08:00
|
|
|
GeodataLoader: "memconservative",
|
2021-12-26 21:20:41 +08:00
|
|
|
UnifiedDelay: false,
|
2019-06-27 17:04:25 +08:00
|
|
|
Authentication: []string{},
|
|
|
|
LogLevel: log.INFO,
|
2019-09-11 17:00:55 +08:00
|
|
|
Hosts: map[string]string{},
|
2019-06-27 17:04:25 +08:00
|
|
|
Rule: []string{},
|
|
|
|
Proxy: []map[string]interface{}{},
|
|
|
|
ProxyGroup: []map[string]interface{}{},
|
2021-11-17 16:03:47 +08:00
|
|
|
Tun: Tun{
|
2022-01-05 01:56:35 +08:00
|
|
|
Enable: false,
|
|
|
|
Stack: "gvisor",
|
2022-01-22 13:24:31 +08:00
|
|
|
DnsHijack: []string{"198.18.0.2:53"},
|
2022-01-27 12:25:53 +08:00
|
|
|
AutoRoute: true,
|
2021-11-17 16:03:47 +08:00
|
|
|
},
|
2020-01-11 00:22:34 +08:00
|
|
|
DNS: RawDNS{
|
2019-05-03 00:05:14 +08:00
|
|
|
Enable: false,
|
2020-08-11 10:28:17 +08:00
|
|
|
UseHosts: true,
|
2019-05-03 00:05:14 +08:00
|
|
|
FakeIPRange: "198.18.0.1/16",
|
2020-01-11 00:22:34 +08:00
|
|
|
FallbackFilter: RawFallbackFilter{
|
2021-08-25 15:15:13 +08:00
|
|
|
GeoIP: true,
|
|
|
|
GeoIPCode: "CN",
|
|
|
|
IPCIDR: []string{},
|
2021-11-17 16:03:47 +08:00
|
|
|
GeoSite: []string{},
|
2019-09-15 13:36:45 +08:00
|
|
|
},
|
2020-02-15 21:42:46 +08:00
|
|
|
DefaultNameserver: []string{
|
|
|
|
"114.114.114.114",
|
2021-11-17 16:03:47 +08:00
|
|
|
"223.5.5.5",
|
2022-01-05 00:33:42 +08:00
|
|
|
"8.8.8.8",
|
|
|
|
"1.0.0.1",
|
|
|
|
},
|
|
|
|
NameServer: []string{
|
2022-01-09 00:36:05 +08:00
|
|
|
"223.5.5.5",
|
|
|
|
"119.29.29",
|
2022-01-05 00:33:42 +08:00
|
|
|
},
|
|
|
|
FakeIPFilter: []string{
|
|
|
|
"dns.msftnsci.com",
|
|
|
|
"www.msftnsci.com",
|
|
|
|
"www.msftconnecttest.com",
|
2020-02-15 21:42:46 +08:00
|
|
|
},
|
2018-12-05 21:52:31 +08:00
|
|
|
},
|
2021-02-18 23:41:50 +08:00
|
|
|
Profile: Profile{
|
|
|
|
StoreSelected: true,
|
|
|
|
},
|
2021-11-17 16:03:47 +08:00
|
|
|
Script: Script{
|
|
|
|
MainCode: "",
|
|
|
|
ShortcutsCode: map[string]string{},
|
|
|
|
},
|
2018-10-02 15:26:36 +08:00
|
|
|
}
|
2020-01-11 00:22:34 +08:00
|
|
|
|
2021-09-13 23:43:28 +08:00
|
|
|
if err := yaml.Unmarshal(buf, rawCfg); err != nil {
|
2018-11-21 13:47:46 +08:00
|
|
|
return nil, err
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
2019-12-01 13:22:47 +08:00
|
|
|
|
2020-01-11 00:22:34 +08:00
|
|
|
return rawCfg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
|
|
|
config := &Config{}
|
|
|
|
|
2019-04-24 12:02:52 +08:00
|
|
|
config.Experimental = &rawCfg.Experimental
|
2021-02-18 23:41:50 +08:00
|
|
|
config.Profile = &rawCfg.Profile
|
2018-07-26 00:04:59 +08:00
|
|
|
|
2018-11-21 13:47:46 +08:00
|
|
|
general, err := parseGeneral(rawCfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
2018-11-21 13:47:46 +08:00
|
|
|
config.General = general
|
2022-01-05 00:33:42 +08:00
|
|
|
|
2021-12-09 23:00:54 +08:00
|
|
|
config.Tun = &rawCfg.Tun
|
2018-07-26 00:04:59 +08:00
|
|
|
|
2019-12-08 12:17:24 +08:00
|
|
|
proxies, providers, err := parseProxies(rawCfg)
|
2018-11-21 13:47:46 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
2018-11-21 13:47:46 +08:00
|
|
|
config.Proxies = proxies
|
2019-12-08 12:17:24 +08:00
|
|
|
config.Providers = providers
|
2018-07-26 00:04:59 +08:00
|
|
|
|
2021-11-17 16:03:47 +08:00
|
|
|
err = parseScript(rawCfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
rules, ruleProviders, err := parseRules(rawCfg, proxies)
|
2018-07-26 00:04:59 +08:00
|
|
|
if err != nil {
|
2018-11-21 13:47:46 +08:00
|
|
|
return nil, err
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
2018-11-21 13:47:46 +08:00
|
|
|
config.Rules = rules
|
2021-11-17 16:03:47 +08:00
|
|
|
config.RuleProviders = ruleProviders
|
2018-07-26 00:04:59 +08:00
|
|
|
|
2020-08-11 10:28:17 +08:00
|
|
|
hosts, err := parseHosts(rawCfg)
|
2018-12-05 21:13:29 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-11 10:28:17 +08:00
|
|
|
config.Hosts = hosts
|
2018-12-05 21:13:29 +08:00
|
|
|
|
2021-11-17 16:03:47 +08:00
|
|
|
dnsCfg, err := parseDNS(rawCfg, hosts, rules)
|
2019-09-11 17:00:55 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-11 10:28:17 +08:00
|
|
|
config.DNS = dnsCfg
|
2019-09-11 17:00:55 +08:00
|
|
|
|
2019-06-27 17:04:25 +08:00
|
|
|
config.Users = parseAuthentication(rawCfg.Authentication)
|
2020-01-11 00:22:34 +08:00
|
|
|
|
2018-11-21 13:47:46 +08:00
|
|
|
return config, nil
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
|
|
|
|
2020-01-11 00:22:34 +08:00
|
|
|
func parseGeneral(cfg *RawConfig) (*General, error) {
|
2018-12-20 01:29:13 +08:00
|
|
|
externalUI := cfg.ExternalUI
|
2022-02-05 02:42:49 +08:00
|
|
|
geodata.SetLoader(cfg.GeodataLoader)
|
2020-06-18 18:11:02 +08:00
|
|
|
// checkout externalUI exist
|
2018-12-21 10:55:21 +08:00
|
|
|
if externalUI != "" {
|
2020-01-30 17:03:11 +08:00
|
|
|
externalUI = C.Path.Resolve(externalUI)
|
2018-12-21 10:55:21 +08:00
|
|
|
|
|
|
|
if _, err := os.Stat(externalUI); os.IsNotExist(err) {
|
|
|
|
return nil, fmt.Errorf("external-ui: %s not exist", externalUI)
|
|
|
|
}
|
2018-12-20 01:29:13 +08:00
|
|
|
}
|
|
|
|
|
2020-06-18 18:11:02 +08:00
|
|
|
return &General{
|
|
|
|
Inbound: Inbound{
|
|
|
|
Port: cfg.Port,
|
|
|
|
SocksPort: cfg.SocksPort,
|
|
|
|
RedirPort: cfg.RedirPort,
|
2020-11-09 10:46:10 +08:00
|
|
|
TProxyPort: cfg.TProxyPort,
|
2020-06-18 18:11:02 +08:00
|
|
|
MixedPort: cfg.MixedPort,
|
|
|
|
AllowLan: cfg.AllowLan,
|
|
|
|
BindAddress: cfg.BindAddress,
|
|
|
|
},
|
|
|
|
Controller: Controller{
|
|
|
|
ExternalController: cfg.ExternalController,
|
|
|
|
ExternalUI: cfg.ExternalUI,
|
|
|
|
Secret: cfg.Secret,
|
|
|
|
},
|
2022-02-05 02:42:49 +08:00
|
|
|
UnifiedDelay: cfg.UnifiedDelay,
|
|
|
|
Mode: cfg.Mode,
|
|
|
|
LogLevel: cfg.LogLevel,
|
|
|
|
IPv6: cfg.IPv6,
|
|
|
|
Interface: cfg.Interface,
|
|
|
|
GeodataLoader: cfg.GeodataLoader,
|
2020-06-18 18:11:02 +08:00
|
|
|
}, nil
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
|
|
|
|
2021-07-04 20:32:59 +08:00
|
|
|
func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]providerTypes.ProxyProvider, err error) {
|
2019-12-08 12:17:24 +08:00
|
|
|
proxies = make(map[string]C.Proxy)
|
2021-07-04 20:32:59 +08:00
|
|
|
providersMap = make(map[string]providerTypes.ProxyProvider)
|
2022-01-05 00:33:42 +08:00
|
|
|
var proxyList []string
|
2021-11-16 20:08:52 +08:00
|
|
|
_proxiesList := list.New()
|
|
|
|
_groupsList := list.New()
|
2018-10-02 15:26:36 +08:00
|
|
|
proxiesConfig := cfg.Proxy
|
|
|
|
groupsConfig := cfg.ProxyGroup
|
2019-12-08 12:17:24 +08:00
|
|
|
providersConfig := cfg.ProxyProvider
|
2018-10-02 15:26:36 +08:00
|
|
|
|
2021-06-10 14:05:56 +08:00
|
|
|
proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect())
|
|
|
|
proxies["REJECT"] = adapter.NewProxy(outbound.NewReject())
|
2022-01-18 21:09:36 +08:00
|
|
|
proxies["COMPATIBLE"] = adapter.NewProxy(outbound.NewCompatible())
|
2019-05-15 14:40:14 +08:00
|
|
|
proxyList = append(proxyList, "DIRECT", "REJECT")
|
2018-07-26 00:04:59 +08:00
|
|
|
|
|
|
|
// parse proxy
|
2018-10-02 15:26:36 +08:00
|
|
|
for idx, mapping := range proxiesConfig {
|
2021-06-10 14:05:56 +08:00
|
|
|
proxy, err := adapter.ParseProxy(mapping)
|
2018-10-02 15:26:36 +08:00
|
|
|
if err != nil {
|
2020-08-25 22:19:59 +08:00
|
|
|
return nil, nil, fmt.Errorf("proxy %d: %w", idx, err)
|
2018-10-27 12:57:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if _, exist := proxies[proxy.Name()]; exist {
|
2020-08-25 22:19:59 +08:00
|
|
|
return nil, nil, fmt.Errorf("proxy %s is the duplicate name", proxy.Name())
|
2018-10-02 15:26:36 +08:00
|
|
|
}
|
2019-12-08 12:17:24 +08:00
|
|
|
proxies[proxy.Name()] = proxy
|
2019-05-15 14:40:14 +08:00
|
|
|
proxyList = append(proxyList, proxy.Name())
|
2021-11-16 20:08:52 +08:00
|
|
|
_proxiesList.PushBack(mapping)
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
|
|
|
|
2020-04-08 15:49:12 +08:00
|
|
|
// keep the original order of ProxyGroups in config file
|
2019-08-28 23:44:32 +08:00
|
|
|
for idx, mapping := range groupsConfig {
|
|
|
|
groupName, existName := mapping["name"].(string)
|
|
|
|
if !existName {
|
2020-08-25 22:19:59 +08:00
|
|
|
return nil, nil, fmt.Errorf("proxy group %d: missing name", idx)
|
2019-08-28 23:44:32 +08:00
|
|
|
}
|
|
|
|
proxyList = append(proxyList, groupName)
|
2021-11-16 20:08:52 +08:00
|
|
|
_groupsList.PushBack(mapping)
|
2019-08-28 23:44:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// check if any loop exists and sort the ProxyGroups
|
2019-12-08 12:17:24 +08:00
|
|
|
if err := proxyGroupsDagSort(groupsConfig); err != nil {
|
|
|
|
return nil, nil, err
|
2019-08-12 10:11:44 +08:00
|
|
|
}
|
2019-08-28 23:44:32 +08:00
|
|
|
|
2019-12-08 12:17:24 +08: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)
|
2018-10-02 15:26:36 +08:00
|
|
|
}
|
|
|
|
|
2019-12-08 12:17:24 +08:00
|
|
|
pd, err := provider.ParseProxyProvider(name, mapping)
|
|
|
|
if err != nil {
|
2020-06-01 00:39:41 +08:00
|
|
|
return nil, nil, fmt.Errorf("parse proxy provider %s error: %w", name, err)
|
2018-10-02 15:26:36 +08:00
|
|
|
}
|
|
|
|
|
2019-12-08 12:17:24 +08:00
|
|
|
providersMap[name] = pd
|
|
|
|
}
|
2019-02-15 14:25:20 +08:00
|
|
|
|
2019-12-08 12:17:24 +08:00
|
|
|
// parse proxy group
|
|
|
|
for idx, mapping := range groupsConfig {
|
|
|
|
group, err := outboundgroup.ParseProxyGroup(mapping, proxies, providersMap)
|
2018-10-02 15:26:36 +08:00
|
|
|
if err != nil {
|
2020-08-25 22:19:59 +08:00
|
|
|
return nil, nil, fmt.Errorf("proxy group[%d]: %w", idx, err)
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
2019-12-08 12:17:24 +08:00
|
|
|
|
|
|
|
groupName := group.Name()
|
|
|
|
if _, exist := proxies[groupName]; exist {
|
2020-08-25 22:19:59 +08:00
|
|
|
return nil, nil, fmt.Errorf("proxy group %s: the duplicate name", groupName)
|
2019-12-08 12:17:24 +08:00
|
|
|
}
|
|
|
|
|
2021-06-10 14:05:56 +08:00
|
|
|
proxies[groupName] = adapter.NewProxy(group)
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
|
|
|
|
2022-01-05 00:33:42 +08:00
|
|
|
var ps []C.Proxy
|
2019-05-15 14:40:14 +08:00
|
|
|
for _, v := range proxyList {
|
|
|
|
ps = append(ps, proxies[v])
|
2018-10-18 23:24:04 +08:00
|
|
|
}
|
2020-11-19 00:53:22 +08:00
|
|
|
hc := provider.NewHealthCheck(ps, "", 0, true)
|
2020-01-11 21:02:55 +08:00
|
|
|
pd, _ := provider.NewCompatibleProvider(provider.ReservedName, ps, hc)
|
2019-12-08 12:17:24 +08:00
|
|
|
providersMap[provider.ReservedName] = pd
|
2018-10-18 23:24:04 +08:00
|
|
|
|
2020-11-13 21:48:52 +08:00
|
|
|
global := outboundgroup.NewSelector(
|
|
|
|
&outboundgroup.GroupCommonOption{
|
|
|
|
Name: "GLOBAL",
|
|
|
|
},
|
2021-07-04 20:32:59 +08:00
|
|
|
[]providerTypes.ProxyProvider{pd},
|
2020-11-13 21:48:52 +08:00
|
|
|
)
|
2021-06-10 14:05:56 +08:00
|
|
|
proxies["GLOBAL"] = adapter.NewProxy(global)
|
2021-11-16 20:08:52 +08:00
|
|
|
ProxiesList = _proxiesList
|
|
|
|
GroupsList = _groupsList
|
|
|
|
if ParsingProxiesCallback != nil {
|
|
|
|
// refresh tray menu
|
|
|
|
go ParsingProxiesCallback(GroupsList, ProxiesList)
|
|
|
|
}
|
2019-12-08 12:17:24 +08:00
|
|
|
return proxies, providersMap, nil
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
|
|
|
|
2021-11-17 16:03:47 +08:00
|
|
|
func parseScript(cfg *RawConfig) error {
|
|
|
|
mode := cfg.Mode
|
|
|
|
script := cfg.Script
|
|
|
|
mainCode := cleanPyKeywords(script.MainCode)
|
|
|
|
shortcutsCode := script.ShortcutsCode
|
|
|
|
|
|
|
|
if mode != T.Script && len(shortcutsCode) == 0 {
|
|
|
|
return nil
|
|
|
|
} else if mode == T.Script && len(mainCode) == 0 {
|
|
|
|
return fmt.Errorf("initialized script module failure, can't find script code in the config file")
|
|
|
|
}
|
|
|
|
|
|
|
|
content :=
|
|
|
|
`# -*- coding: UTF-8 -*-
|
|
|
|
|
|
|
|
from datetime import datetime as whatever
|
|
|
|
|
|
|
|
class ClashTime:
|
|
|
|
def now(self):
|
|
|
|
return whatever.now()
|
|
|
|
|
|
|
|
def unix(self):
|
|
|
|
return int(whatever.now().timestamp())
|
|
|
|
|
|
|
|
def unix_nano(self):
|
|
|
|
return int(round(whatever.now().timestamp() * 1000))
|
|
|
|
|
|
|
|
time = ClashTime()
|
|
|
|
|
|
|
|
`
|
|
|
|
for k, v := range shortcutsCode {
|
|
|
|
v = cleanPyKeywords(v)
|
|
|
|
v = strings.TrimSpace(v)
|
|
|
|
if len(v) == 0 {
|
|
|
|
return fmt.Errorf("initialized rule SCRIPT failure, shortcut [%s] code invalid syntax", k)
|
|
|
|
}
|
|
|
|
|
|
|
|
content += "def " + strings.ToLower(k) + "(ctx, network, process_name, host, src_ip, src_port, dst_ip, dst_port):\n return " + v + "\n\n"
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-12-02 22:56:17 +08: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 02:42:49 +08:00
|
|
|
startTime := time.Now()
|
2021-12-02 22:56:17 +08:00
|
|
|
// parse rule provider
|
|
|
|
for name, mapping := range cfg.RuleProvider {
|
2022-01-22 22:10:45 +08:00
|
|
|
rp, err := RP.ParseRuleProvider(name, mapping)
|
2021-12-02 22:56:17 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ruleProviders[name] = &rp
|
2022-01-22 22:10:45 +08:00
|
|
|
RP.SetRuleProvider(rp)
|
2021-12-02 22:56:17 +08:00
|
|
|
}
|
|
|
|
|
2022-01-05 00:33:42 +08:00
|
|
|
var rules []C.Rule
|
2018-10-02 15:26:36 +08:00
|
|
|
rulesConfig := cfg.Rule
|
2021-11-17 16:03:47 +08:00
|
|
|
mode := cfg.Mode
|
|
|
|
|
2018-07-26 00:04:59 +08:00
|
|
|
// parse rules
|
2018-11-21 18:21:24 +08:00
|
|
|
for idx, line := range rulesConfig {
|
|
|
|
rule := trimArr(strings.Split(line, ","))
|
|
|
|
var (
|
2021-11-17 16:03:47 +08:00
|
|
|
payload string
|
|
|
|
target string
|
2022-01-05 00:33:42 +08:00
|
|
|
params []string
|
2021-11-17 16:03:47 +08:00
|
|
|
ruleName = strings.ToUpper(rule[0])
|
2018-11-21 18:21:24 +08:00
|
|
|
)
|
|
|
|
|
2021-11-17 16:03:47 +08:00
|
|
|
if mode == T.Script && ruleName != "GEOSITE" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-01-22 22:10:45 +08:00
|
|
|
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" {
|
|
|
|
payload = strings.Join(rule[1:len(rule)-1], ",")
|
|
|
|
target = rule[len(rule)-1]
|
|
|
|
} else {
|
|
|
|
switch l := len(rule); {
|
|
|
|
case l == 2:
|
2021-11-17 16:03:47 +08:00
|
|
|
target = rule[1]
|
2022-01-22 22:10:45 +08:00
|
|
|
case l == 3:
|
|
|
|
if ruleName == "MATCH" {
|
|
|
|
payload = ""
|
|
|
|
target = rule[1]
|
|
|
|
params = rule[2:]
|
|
|
|
break
|
|
|
|
}
|
|
|
|
payload = rule[1]
|
|
|
|
target = rule[2]
|
|
|
|
case l >= 4:
|
|
|
|
payload = rule[1]
|
|
|
|
target = rule[2]
|
|
|
|
params = rule[3:]
|
|
|
|
default:
|
|
|
|
return nil, nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
2018-11-21 18:21:24 +08:00
|
|
|
|
2021-11-17 16:03:47 +08:00
|
|
|
if _, ok := proxies[target]; mode != T.Script && !ok {
|
|
|
|
return nil, nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target)
|
2019-06-20 11:03:50 +08:00
|
|
|
}
|
|
|
|
|
2019-10-28 00:02:23 +08:00
|
|
|
params = trimArr(params)
|
2019-03-30 14:11:59 +08:00
|
|
|
|
2022-01-23 18:27:44 +08:00
|
|
|
if ruleName == "GEOSITE" {
|
|
|
|
if err := initGeoSite(); err != nil {
|
|
|
|
return nil, nil, fmt.Errorf("can't initial GeoSite: %w", err)
|
|
|
|
}
|
|
|
|
}
|
2021-11-17 16:03:47 +08:00
|
|
|
parsed, parseErr := R.ParseRule(ruleName, payload, target, params)
|
2019-10-28 00:02:23 +08:00
|
|
|
if parseErr != nil {
|
2021-11-17 16:03:47 +08:00
|
|
|
return nil, nil, fmt.Errorf("rules[%d] [%s] error: %s", idx, line, parseErr.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
if mode != T.Script {
|
|
|
|
rules = append(rules, parsed)
|
2019-03-30 14:11:59 +08:00
|
|
|
}
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
2022-02-05 02:42:49 +08:00
|
|
|
elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms
|
|
|
|
log.Infoln("Initialization time consuming %dms", elapsedTime) //Segment finished in xxm
|
|
|
|
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
|
2021-11-17 16:03:47 +08:00
|
|
|
runtime.GC()
|
2019-03-30 14:11:59 +08:00
|
|
|
|
2021-11-17 16:03:47 +08:00
|
|
|
return rules, ruleProviders, nil
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
2018-12-05 21:13:29 +08:00
|
|
|
|
2020-05-28 12:13:05 +08:00
|
|
|
func parseHosts(cfg *RawConfig) (*trie.DomainTrie, error) {
|
2019-09-11 17:00:55 +08:00
|
|
|
tree := trie.New()
|
2020-06-07 17:25:51 +08:00
|
|
|
|
|
|
|
// add default hosts
|
|
|
|
if err := tree.Insert("localhost", net.IP{127, 0, 0, 1}); err != nil {
|
2020-09-20 15:53:27 +08:00
|
|
|
log.Errorln("insert localhost to host error: %s", err.Error())
|
2020-06-07 17:25:51 +08:00
|
|
|
}
|
|
|
|
|
2019-09-11 17:00:55 +08:00
|
|
|
if len(cfg.Hosts) != 0 {
|
|
|
|
for domain, ipStr := range cfg.Hosts {
|
|
|
|
ip := net.ParseIP(ipStr)
|
|
|
|
if ip == nil {
|
|
|
|
return nil, fmt.Errorf("%s is not a valid IP", ipStr)
|
|
|
|
}
|
2021-11-17 16:03:47 +08:00
|
|
|
_ = tree.Insert(domain, ip)
|
2019-09-11 17:00:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tree, nil
|
|
|
|
}
|
|
|
|
|
2020-02-17 22:13:15 +08:00
|
|
|
func hostWithDefaultPort(host string, defPort string) (string, error) {
|
2018-12-05 21:13:29 +08:00
|
|
|
if !strings.Contains(host, ":") {
|
|
|
|
host += ":"
|
|
|
|
}
|
|
|
|
|
|
|
|
hostname, port, err := net.SplitHostPort(host)
|
|
|
|
if err != nil {
|
2020-02-17 22:13:15 +08:00
|
|
|
return "", err
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if port == "" {
|
|
|
|
port = defPort
|
|
|
|
}
|
|
|
|
|
2020-02-17 22:13:15 +08:00
|
|
|
return net.JoinHostPort(hostname, port), nil
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func parseNameServer(servers []string) ([]dns.NameServer, error) {
|
2022-01-05 00:33:42 +08:00
|
|
|
var nameservers []dns.NameServer
|
2018-12-05 21:13:29 +08:00
|
|
|
|
|
|
|
for idx, server := range servers {
|
|
|
|
// parse without scheme .e.g 8.8.8.8:53
|
2019-03-01 00:52:30 +08:00
|
|
|
if !strings.Contains(server, "://") {
|
|
|
|
server = "udp://" + server
|
2018-12-05 21:13:29 +08: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 22:13:15 +08:00
|
|
|
var addr, dnsNetType string
|
2019-03-01 00:52:30 +08:00
|
|
|
switch u.Scheme {
|
|
|
|
case "udp":
|
2020-02-17 22:13:15 +08:00
|
|
|
addr, err = hostWithDefaultPort(u.Host, "53")
|
2019-03-01 00:52:30 +08:00
|
|
|
dnsNetType = "" // UDP
|
|
|
|
case "tcp":
|
2020-02-17 22:13:15 +08:00
|
|
|
addr, err = hostWithDefaultPort(u.Host, "53")
|
2019-03-01 00:52:30 +08:00
|
|
|
dnsNetType = "tcp" // TCP
|
|
|
|
case "tls":
|
2020-02-17 22:13:15 +08:00
|
|
|
addr, err = hostWithDefaultPort(u.Host, "853")
|
2019-03-01 00:52:30 +08:00
|
|
|
dnsNetType = "tcp-tls" // DNS over TLS
|
2019-06-28 12:29:08 +08:00
|
|
|
case "https":
|
|
|
|
clearURL := url.URL{Scheme: "https", Host: u.Host, Path: u.Path}
|
2020-02-15 21:42:46 +08:00
|
|
|
addr = clearURL.String()
|
2019-06-28 12:29:08 +08:00
|
|
|
dnsNetType = "https" // DNS over HTTPS
|
2021-09-06 23:07:34 +08:00
|
|
|
case "dhcp":
|
|
|
|
addr = u.Host
|
|
|
|
dnsNetType = "dhcp" // UDP from DHCP
|
2022-01-27 12:25:53 +08:00
|
|
|
case "quic":
|
|
|
|
addr, err = hostWithDefaultPort(u.Host, "784")
|
|
|
|
dnsNetType = "quic" // DNS over QUIC
|
2019-03-01 00:52:30 +08:00
|
|
|
default:
|
2018-12-05 21:13:29 +08:00
|
|
|
return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme)
|
|
|
|
}
|
2019-06-28 12:29:08 +08:00
|
|
|
|
2019-03-01 00:52:30 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error())
|
|
|
|
}
|
2018-12-05 21:13:29 +08:00
|
|
|
|
|
|
|
nameservers = append(
|
|
|
|
nameservers,
|
|
|
|
dns.NameServer{
|
2021-11-17 16:03:47 +08:00
|
|
|
Net: dnsNetType,
|
|
|
|
Addr: addr,
|
|
|
|
ProxyAdapter: u.Fragment,
|
2018-12-05 21:13:29 +08:00
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return nameservers, nil
|
|
|
|
}
|
|
|
|
|
2021-05-19 11:17:35 +08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-09-15 13:36:45 +08:00
|
|
|
func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
|
2022-01-05 00:33:42 +08:00
|
|
|
var ipNets []*net.IPNet
|
2019-09-15 13:36:45 +08:00
|
|
|
|
|
|
|
for idx, ip := range ips {
|
|
|
|
_, ipnet, err := net.ParseCIDR(ip)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %s", idx, err.Error())
|
|
|
|
}
|
|
|
|
ipNets = append(ipNets, ipnet)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ipNets, nil
|
|
|
|
}
|
|
|
|
|
2021-11-17 16:03:47 +08:00
|
|
|
func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainMatcher, error) {
|
2022-01-05 00:33:42 +08:00
|
|
|
var sites []*router.DomainMatcher
|
2022-01-11 22:17:24 +08:00
|
|
|
if len(countries) > 0 {
|
|
|
|
if err := initGeoSite(); err != nil {
|
|
|
|
return nil, fmt.Errorf("can't initial GeoSite: %w", err)
|
|
|
|
}
|
|
|
|
}
|
2021-11-17 16:03:47 +08: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
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie, rules []C.Rule) (*DNS, error) {
|
2021-10-11 20:48:58 +08:00
|
|
|
cfg := rawCfg.DNS
|
2018-12-05 21:13:29 +08:00
|
|
|
if cfg.Enable && len(cfg.NameServer) == 0 {
|
2020-08-25 22:19:59 +08:00
|
|
|
return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty")
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
dnsCfg := &DNS{
|
|
|
|
Enable: cfg.Enable,
|
|
|
|
Listen: cfg.Listen,
|
2019-06-29 00:58:59 +08:00
|
|
|
IPv6: cfg.IPv6,
|
2018-12-05 21:13:29 +08:00
|
|
|
EnhancedMode: cfg.EnhancedMode,
|
2019-09-15 13:36:45 +08:00
|
|
|
FallbackFilter: FallbackFilter{
|
2021-11-17 16:03:47 +08:00
|
|
|
IPCIDR: []*net.IPNet{},
|
|
|
|
GeoSite: []*router.DomainMatcher{},
|
2019-09-15 13:36:45 +08:00
|
|
|
},
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
2019-03-01 00:52:30 +08:00
|
|
|
var err error
|
|
|
|
if dnsCfg.NameServer, err = parseNameServer(cfg.NameServer); err != nil {
|
|
|
|
return nil, err
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
2019-03-01 00:52:30 +08:00
|
|
|
if dnsCfg.Fallback, err = parseNameServer(cfg.Fallback); err != nil {
|
|
|
|
return nil, err
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
2021-05-19 11:17:35 +08:00
|
|
|
if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-15 21:42:46 +08:00
|
|
|
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 22:13:15 +08:00
|
|
|
host, _, err := net.SplitHostPort(ns.Addr)
|
|
|
|
if err != nil || net.ParseIP(host) == nil {
|
2020-02-15 21:42:46 +08:00
|
|
|
return nil, errors.New("default nameserver should be pure IP")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-18 21:08:27 +08:00
|
|
|
if cfg.EnhancedMode == C.DNSFakeIP {
|
2019-05-03 00:05:14 +08:00
|
|
|
_, ipnet, err := net.ParseCIDR(cfg.FakeIPRange)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-12-28 00:10:06 +08:00
|
|
|
|
2020-05-28 12:13:05 +08:00
|
|
|
var host *trie.DomainTrie
|
2019-12-28 00:10:06 +08:00
|
|
|
// fake ip skip host filter
|
|
|
|
if len(cfg.FakeIPFilter) != 0 {
|
|
|
|
host = trie.New()
|
|
|
|
for _, domain := range cfg.FakeIPFilter {
|
2021-11-17 16:03:47 +08:00
|
|
|
_ = host.Insert(domain, true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(dnsCfg.Fallback) != 0 {
|
|
|
|
if host == nil {
|
|
|
|
host = trie.New()
|
|
|
|
}
|
|
|
|
for _, fb := range dnsCfg.Fallback {
|
|
|
|
if net.ParseIP(fb.Addr) != nil {
|
|
|
|
continue
|
|
|
|
}
|
2022-01-05 00:33:42 +08:00
|
|
|
_ = host.Insert(fb.Addr, true)
|
2019-12-28 00:10:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 20:48:58 +08:00
|
|
|
pool, err := fakeip.New(fakeip.Options{
|
|
|
|
IPNet: ipnet,
|
|
|
|
Size: 1000,
|
|
|
|
Host: host,
|
|
|
|
Persistence: rawCfg.Profile.StoreFakeIP,
|
|
|
|
})
|
2019-05-03 00:05:14 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
dnsCfg.FakeIPRange = pool
|
|
|
|
}
|
|
|
|
|
2021-11-17 16:03:47 +08: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 13:36:45 +08:00
|
|
|
}
|
|
|
|
|
2020-08-11 10:28:17 +08:00
|
|
|
if cfg.UseHosts {
|
|
|
|
dnsCfg.Hosts = hosts
|
|
|
|
}
|
|
|
|
|
2018-12-05 21:13:29 +08:00
|
|
|
return dnsCfg, nil
|
|
|
|
}
|
2019-06-27 17:04:25 +08:00
|
|
|
|
|
|
|
func parseAuthentication(rawRecords []string) []auth.AuthUser {
|
|
|
|
users := make([]auth.AuthUser, 0)
|
|
|
|
for _, line := range rawRecords {
|
|
|
|
userData := strings.SplitN(line, ":", 2)
|
|
|
|
if len(userData) == 2 {
|
|
|
|
users = append(users, auth.AuthUser{User: userData[0], Pass: userData[1]})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return users
|
|
|
|
}
|
2021-11-17 16:03:47 +08:00
|
|
|
|
|
|
|
func cleanPyKeywords(code string) string {
|
|
|
|
if len(code) == 0 {
|
|
|
|
return code
|
|
|
|
}
|
|
|
|
keywords := []string{"import", "print"}
|
|
|
|
|
|
|
|
for _, kw := range keywords {
|
|
|
|
reg := regexp.MustCompile("(?m)[\r\n]+^.*" + kw + ".*$")
|
|
|
|
code = reg.ReplaceAllString(code, "")
|
|
|
|
}
|
|
|
|
return code
|
|
|
|
}
|