2018-07-25 16:04:59 +00:00
package config
import (
2021-11-16 12:08:52 +00:00
"container/list"
2020-02-15 13:42:46 +00:00
"errors"
2018-07-25 16:04:59 +00:00
"fmt"
2022-01-22 14:10:45 +00:00
R "github.com/Dreamacro/clash/rule"
RP "github.com/Dreamacro/clash/rule/provider"
2018-12-05 13:13:29 +00:00
"net"
2022-03-11 18:16:13 +00:00
"net/netip"
2018-12-05 13:13:29 +00:00
"net/url"
2018-07-25 16:04:59 +00:00
"os"
2021-11-17 08:03:47 +00:00
"regexp"
"runtime"
2018-07-25 16:04:59 +00:00
"strings"
2022-02-04 18:42:49 +00:00
"time"
2018-07-25 16:04:59 +00:00
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"
2019-06-27 09:04:25 +00:00
"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"
2020-05-28 04:13:05 +00:00
"github.com/Dreamacro/clash/component/trie"
2018-07-25 16:04:59 +00:00
C "github.com/Dreamacro/clash/constant"
2021-07-04 12:32:59 +00:00
providerTypes "github.com/Dreamacro/clash/constant/provider"
2018-12-05 13:13:29 +00:00
"github.com/Dreamacro/clash/dns"
2022-03-08 21:08:35 +00:00
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
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-07-25 16:04:59 +00:00
)
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" `
2022-02-05 17:59:35 +00:00
AutoIptables bool ` json:"auto-iptables" `
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" `
2020-11-09 02:46:10 +00:00
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 {
2020-02-15 13:42:46 +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" `
2021-10-18 13:08:27 +00:00
EnhancedMode C . DNSMode ` yaml:"enhanced-mode" `
2020-02-15 13:42:46 +00:00
DefaultNameserver [ ] dns . NameServer ` yaml:"default-nameserver" `
FakeIPRange * fakeip . Pool
2020-08-11 02:28:17 +00:00
Hosts * trie . DomainTrie
2021-05-19 03:17:35 +00:00
NameServerPolicy map [ string ] 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" `
IPCIDR [ ] * net . IPNet ` yaml:"ipcidr" `
Domain [ ] string ` yaml:"domain" `
GeoSite [ ] * router . DomainMatcher ` yaml:"geosite" `
2018-10-02 07:26:36 +00:00
}
2021-11-16 12:08:52 +00:00
var (
GroupsList = list . New ( )
ProxiesList = list . New ( )
ParsingProxiesCallback func ( groupsList * list . List , proxiesList * list . List )
)
2021-02-18 15:41:50 +00:00
// Profile config
type Profile struct {
StoreSelected bool ` yaml:"store-selected" `
2021-11-08 12:48:29 +00:00
StoreFakeIP bool ` yaml:"store-fake-ip" `
2021-02-18 15:41:50 +00:00
}
2021-11-17 08:03:47 +00:00
// Tun config
type Tun struct {
2022-03-11 18:16:13 +00:00
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
}
// Script config
type Script struct {
MainCode string ` yaml:"code" json:"code" `
ShortcutsCode map [ string ] string ` yaml:"shortcuts" json:"shortcuts" `
}
2019-04-24 04:02:52 +00:00
// Experimental config
2020-06-27 06:19:31 +00:00
type Experimental struct { }
2019-04-24 04:02:52 +00:00
2021-11-25 16:57:33 +00:00
// Config is clash config manager
2018-07-25 16:04:59 +00:00
type Config struct {
2021-11-17 08:03:47 +00: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 14:56:17 +00:00
RuleProviders map [ string ] * providerTypes . RuleProvider
2018-07-25 16:04:59 +00:00
}
2020-01-10 16:22:34 +00:00
type RawDNS struct {
2020-02-15 13:42:46 +00:00
Enable bool ` yaml:"enable" `
IPv6 bool ` yaml:"ipv6" `
2020-08-11 02:28:17 +00:00
UseHosts bool ` yaml:"use-hosts" `
2020-02-15 13:42:46 +00:00
NameServer [ ] string ` yaml:"nameserver" `
Fallback [ ] string ` yaml:"fallback" `
FallbackFilter RawFallbackFilter ` yaml:"fallback-filter" `
Listen string ` yaml:"listen" `
2021-10-18 13:08:27 +00:00
EnhancedMode C . DNSMode ` yaml:"enhanced-mode" `
2020-02-15 13:42:46 +00:00
FakeIPRange string ` yaml:"fake-ip-range" `
FakeIPFilter [ ] string ` yaml:"fake-ip-filter" `
DefaultNameserver [ ] string ` yaml:"default-nameserver" `
2021-05-19 03:17:35 +00:00
NameServerPolicy map [ string ] string ` yaml:"nameserver-policy" `
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" `
}
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" `
2020-11-09 02:46:10 +00:00
TProxyPort int ` yaml:"tproxy-port" `
2020-05-12 03:29:53 +00:00
MixedPort int ` yaml:"mixed-port" `
2019-06-27 09:04:25 +00:00
Authentication [ ] string ` yaml:"authentication" `
2018-12-05 13:13:29 +00:00
AllowLan bool ` yaml:"allow-lan" `
2019-08-08 05:45:07 +00:00
BindAddress string ` yaml:"bind-address" `
2020-02-15 13:42:46 +00:00
Mode T . TunnelMode ` yaml:"mode" `
2021-12-26 13:20:41 +00:00
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" `
2020-06-27 06:19:31 +00:00
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-02-05 17:59:35 +00:00
AutoIptables bool ` yaml:"auto-iptables" `
2018-12-05 13:13:29 +00:00
2022-03-16 04:10:13 +00:00
ProxyProvider map [ string ] map [ string ] any ` yaml:"proxy-providers" `
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" `
2022-03-16 12:16:30 +00:00
Tun RawTun ` yaml:"tun" `
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" `
2022-03-17 09:41:02 +00:00
Script Script ` yaml:"script" `
2018-12-05 13:13:29 +00:00
}
2019-12-01 05:22:47 +00:00
// 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 ) {
2021-02-18 15:41:50 +00:00
// config with default value
2020-01-10 16:22:34 +00:00
rawCfg := & RawConfig {
2019-06-27 09:04:25 +00:00
AllowLan : false ,
2019-08-08 05:45:07 +00:00
BindAddress : "*" ,
2019-06-27 09:04:25 +00:00
Mode : T . Rule ,
2022-03-16 09:29:09 +00:00
GeodataMode : C . GeodataMode ,
2022-02-04 16:51:06 +00:00
GeodataLoader : "memconservative" ,
2022-02-05 17:59:35 +00:00
AutoIptables : false ,
2021-12-26 13:20:41 +00:00
UnifiedDelay : false ,
2019-06-27 09:04:25 +00:00
Authentication : [ ] string { } ,
LogLevel : log . INFO ,
2019-09-11 09:00:55 +00:00
Hosts : map [ string ] string { } ,
2019-06-27 09:04:25 +00:00
Rule : [ ] string { } ,
2022-03-16 04:10:13 +00:00
Proxy : [ ] map [ string ] any { } ,
ProxyGroup : [ ] map [ string ] any { } ,
2022-03-17 09:41:02 +00:00
Tun : RawTun {
2022-01-04 17:56:35 +00:00
Enable : false ,
2022-03-17 09:41:02 +00:00
Device : "" ,
Stack : C . TunGvisor ,
DNSHijack : [ ] string { "198.18.0.2:53" } , // default hijack all dns query
AutoRoute : true ,
} ,
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
} ,
2020-02-15 13:42:46 +00:00
DefaultNameserver : [ ] string {
"114.114.114.114" ,
2021-11-17 08:03:47 +00:00
"223.5.5.5" ,
2022-01-04 16:33:42 +00:00
"8.8.8.8" ,
"1.0.0.1" ,
} ,
NameServer : [ ] string {
2022-01-08 16:36:05 +00:00
"223.5.5.5" ,
2022-03-15 15:13:41 +00:00
"119.29.29.29" ,
2022-03-08 21:08:35 +00:00
"https://doh.pub/dns-query" ,
"tls://223.5.5.5:853" ,
2022-01-04 16:33:42 +00:00
} ,
FakeIPFilter : [ ] string {
"dns.msftnsci.com" ,
"www.msftnsci.com" ,
"www.msftconnecttest.com" ,
2020-02-15 13:42:46 +00:00
} ,
2018-12-05 13:52:31 +00:00
} ,
2021-02-18 15:41:50 +00:00
Profile : Profile {
StoreSelected : true ,
} ,
2021-11-17 08:03:47 +00:00
Script : Script {
MainCode : "" ,
ShortcutsCode : map [ string ] string { } ,
} ,
2018-10-02 07:26:36 +00:00
}
2020-01-10 16:22:34 +00:00
2021-09-13 15:43:28 +00:00
if err := yaml . Unmarshal ( buf , rawCfg ) ; err != nil {
2018-11-21 05:47:46 +00:00
return nil , err
2018-07-25 16:04:59 +00:00
}
2019-12-01 05:22:47 +00:00
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 ( )
2019-04-24 04:02:52 +00:00
config . Experimental = & rawCfg . Experimental
2021-02-18 15:41:50 +00:00
config . Profile = & rawCfg . Profile
2018-07-25 16:04:59 +00:00
2018-11-21 05:47:46 +00:00
general , err := parseGeneral ( rawCfg )
if err != nil {
return nil , err
2018-07-25 16:04:59 +00:00
}
2018-11-21 05:47:46 +00:00
config . General = general
2022-01-04 16:33:42 +00:00
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 )
2018-07-25 16:04:59 +00:00
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-07-25 16:04:59 +00:00
}
2018-11-21 05:47:46 +00:00
config . Proxies = proxies
2019-12-08 04:17:24 +00:00
config . Providers = providers
2018-07-25 16:04:59 +00:00
2021-11-17 08:03:47 +00:00
err = parseScript ( rawCfg )
if err != nil {
return nil , err
}
rules , ruleProviders , err := parseRules ( rawCfg , proxies )
2018-07-25 16:04:59 +00:00
if err != nil {
2018-11-21 05:47:46 +00:00
return nil , err
2018-07-25 16:04:59 +00:00
}
2018-11-21 05:47:46 +00:00
config . Rules = rules
2021-11-17 08:03:47 +00:00
config . RuleProviders = ruleProviders
2018-07-25 16:04:59 +00:00
2020-08-11 02:28:17 +00:00
hosts , err := parseHosts ( rawCfg )
2018-12-05 13:13:29 +00:00
if err != nil {
return nil , err
}
2020-08-11 02:28:17 +00:00
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
}
2020-08-11 02:28:17 +00:00
config . DNS = dnsCfg
2019-09-11 09:00:55 +00:00
2019-06-27 09:04:25 +00:00
config . Users = parseAuthentication ( rawCfg . Authentication )
2020-01-10 16:22:34 +00:00
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
2018-07-25 16:04:59 +00:00
}
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 ,
2020-11-09 02:46:10 +00:00
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 ,
2022-02-05 17:59:35 +00:00
AutoIptables : cfg . AutoIptables ,
2020-06-18 10:11:02 +00:00
} , nil
2018-07-25 16:04:59 +00:00
}
2021-07-04 12:32:59 +00:00
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 )
2021-07-04 12:32:59 +00:00
providersMap = make ( map [ string ] providerTypes . ProxyProvider )
2018-10-02 07:26:36 +00:00
proxiesConfig := cfg . Proxy
groupsConfig := cfg . ProxyGroup
2019-12-08 04:17:24 +00:00
providersConfig := cfg . ProxyProvider
2018-10-02 07:26:36 +00:00
2022-03-14 18:55:06 +00:00
var proxyList [ ] string
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 ( ) )
2022-01-18 13:09:36 +00:00
proxies [ "COMPATIBLE" ] = adapter . NewProxy ( outbound . NewCompatible ( ) )
2019-05-15 06:40:14 +00:00
proxyList = append ( proxyList , "DIRECT" , "REJECT" )
2018-07-25 16:04:59 +00:00
// parse proxy
2018-10-02 07:26:36 +00:00
for idx , mapping := range proxiesConfig {
2021-06-10 06:05:56 +00:00
proxy , err := adapter . ParseProxy ( mapping )
2018-10-02 07:26:36 +00:00
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 ( ) )
2018-10-02 07:26:36 +00:00
}
2019-12-08 04:17:24 +00:00
proxies [ proxy . Name ( ) ] = proxy
2019-05-15 06:40:14 +00:00
proxyList = append ( proxyList , proxy . Name ( ) )
2021-11-16 12:08:52 +00:00
_proxiesList . PushBack ( mapping )
2018-07-25 16:04:59 +00:00
}
2020-04-08 07:49:12 +00:00
// keep the original order of ProxyGroups in config file
2019-08-28 15:44:32 +00:00
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 )
2019-08-28 15:44:32 +00:00
}
proxyList = append ( proxyList , groupName )
2021-11-16 12:08:52 +00:00
_groupsList . PushBack ( mapping )
2019-08-28 15:44:32 +00:00
}
// 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-08-12 02:11:44 +00:00
}
2019-08-28 15:44:32 +00:00
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 )
2018-10-02 07:26:36 +00:00
}
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 )
2018-10-02 07:26:36 +00:00
}
2019-12-08 04:17:24 +00:00
providersMap [ name ] = pd
}
2019-02-15 06:25:20 +00:00
2022-03-14 18:55:06 +00:00
for _ , proxyProvider := range providersMap {
log . Infoln ( "Start initial provider %s" , proxyProvider . Name ( ) )
if err := proxyProvider . Initial ( ) ; err != nil {
return nil , nil , fmt . Errorf ( "initial proxy provider %s error: %w" , proxyProvider . Name ( ) , err )
2018-10-02 07:26:36 +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 )
2018-10-02 07:26:36 +00:00
if err != nil {
2020-08-25 14:19:59 +00:00
return nil , nil , fmt . Errorf ( "proxy group[%d]: %w" , idx , err )
2018-07-25 16:04:59 +00:00
}
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 )
2018-07-25 16:04:59 +00:00
}
2020-01-11 13:02:55 +00:00
// initial compatible provider
2019-12-10 09:27:07 +00:00
for _ , pd := range providersMap {
2021-07-04 12:32:59 +00:00
if pd . VehicleType ( ) != providerTypes . Compatible {
2019-12-10 09:27:07 +00:00
continue
}
log . Infoln ( "Start initial compatible provider %s" , pd . Name ( ) )
if err := pd . Initial ( ) ; err != nil {
return nil , nil , err
}
}
2022-03-14 18:55:06 +00:00
var ps [ ] C . Proxy
2019-05-15 06:40:14 +00:00
for _ , v := range proxyList {
ps = append ( ps , proxies [ v ] )
2018-10-18 15:24:04 +00:00
}
2020-11-18 16:53:22 +00:00
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
2018-10-18 15:24:04 +00:00
2020-11-13 13:48:52 +00:00
global := outboundgroup . NewSelector (
& outboundgroup . GroupCommonOption {
Name : "GLOBAL" ,
} ,
2021-07-04 12:32:59 +00:00
[ ] providerTypes . ProxyProvider { pd } ,
2020-11-13 13:48:52 +00:00
)
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
2018-07-25 16:04:59 +00:00
}
2021-11-17 08:03:47 +00: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 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 {
2022-01-22 14:10:45 +00:00
rp , err := RP . ParseRuleProvider ( name , mapping )
2021-12-02 14:56:17 +00:00
if err != nil {
return nil , nil , err
}
ruleProviders [ name ] = & rp
2022-01-22 14:10:45 +00:00
RP . SetRuleProvider ( rp )
2021-12-02 14:56:17 +00:00
}
2022-01-04 16:33:42 +00:00
var rules [ ] C . Rule
2018-10-02 07:26:36 +00:00
rulesConfig := cfg . Rule
2021-11-17 08:03:47 +00:00
mode := cfg . Mode
2018-07-25 16:04:59 +00:00
// parse rules
2018-11-21 10:21:24 +00:00
for idx , line := range rulesConfig {
rule := trimArr ( strings . Split ( line , "," ) )
var (
2021-11-17 08:03:47 +00:00
payload string
target string
2022-01-04 16:33:42 +00:00
params [ ] string
2021-11-17 08:03:47 +00:00
ruleName = strings . ToUpper ( rule [ 0 ] )
2018-11-21 10:21:24 +00:00
)
2021-11-17 08:03:47 +00:00
if mode == T . Script && ruleName != "GEOSITE" {
continue
}
2022-03-17 09:41:02 +00:00
l := len ( rule )
2022-03-14 18:55:06 +00:00
2022-01-22 14:10:45 +00:00
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" {
2022-03-17 09:41:02 +00:00
target = rule [ l - 1 ]
payload = strings . Join ( rule [ 1 : l - 1 ] , "," )
2022-01-22 14:10:45 +00:00
} else {
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 )
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
2022-01-22 14:10:45 +00:00
payload = rule [ 1 ]
2022-03-17 09:41:02 +00:00
}
target = rule [ l - 1 ]
params = rule [ l : ]
2018-07-25 16:04:59 +00:00
}
2018-11-21 10:21:24 +00:00
2021-11-17 08:03:47 +00: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 03:03:50 +00:00
}
2019-10-27 16:02:23 +00:00
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 )
2019-10-27 16:02:23 +00:00
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 ( ) )
}
if mode != T . Script {
rules = append ( rules , parsed )
2019-03-30 06:11:59 +00:00
}
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-07-25 16:04:59 +00:00
}
2018-12-05 13:13:29 +00:00
2020-05-28 04:13:05 +00:00
func parseHosts ( cfg * RawConfig ) ( * trie . DomainTrie , error ) {
2019-09-11 09:00:55 +00:00
tree := trie . New ( )
2020-06-07 09:25:51 +00:00
// add default hosts
if err := tree . Insert ( "localhost" , net . IP { 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 {
ip := net . ParseIP ( ipStr )
if ip == nil {
return nil , fmt . Errorf ( "%s is not a valid IP" , ipStr )
}
tree . Insert ( domain , ip )
}
}
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 ) {
nameservers := [ ] dns . NameServer { }
for idx , server := range servers {
// parse without scheme .e.g 8.8.8.8:53
2019-02-28 16:52:30 +00:00
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
2019-02-28 16:52:30 +00:00
switch u . Scheme {
case "udp" :
2020-02-17 14:13:15 +00:00
addr , err = hostWithDefaultPort ( u . Host , "53" )
2019-02-28 16:52:30 +00:00
dnsNetType = "" // UDP
case "tcp" :
2020-02-17 14:13:15 +00:00
addr , err = hostWithDefaultPort ( u . Host , "53" )
2019-02-28 16:52:30 +00:00
dnsNetType = "tcp" // TCP
case "tls" :
2020-02-17 14:13:15 +00:00
addr , err = hostWithDefaultPort ( u . Host , "853" )
2019-02-28 16:52:30 +00:00
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 }
2020-02-15 13:42:46 +00:00
addr = clearURL . String ( )
2019-06-28 04:29:08 +00:00
dnsNetType = "https" // DNS over HTTPS
2021-09-06 15:07:34 +00:00
case "dhcp" :
addr = u . Host
dnsNetType = "dhcp" // UDP from DHCP
2022-01-27 04:25:53 +00:00
case "quic" :
addr , err = hostWithDefaultPort ( u . Host , "784" )
dnsNetType = "quic" // DNS over QUIC
2019-02-28 16:52:30 +00:00
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
2019-02-28 16:52:30 +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 ,
2022-03-11 18:16:13 +00:00
Interface : dialer . DefaultInterface . Load ( ) ,
2018-12-05 13:13:29 +00:00
} ,
)
}
return nameservers , nil
}
2021-05-19 03:17:35 +00: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 05:36:45 +00:00
func parseFallbackIPCIDR ( ips [ ] string ) ( [ ] * net . IPNet , error ) {
ipNets := [ ] * net . IPNet { }
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 08:03:47 +00:00
func parseFallbackGeoSite ( countries [ ] string , rules [ ] C . Rule ) ( [ ] * router . DomainMatcher , error ) {
2022-01-04 16:33:42 +00:00
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
}
func parseDNS ( rawCfg * RawConfig , hosts * trie . DomainTrie , 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 ,
2019-06-28 16:58:59 +00:00
IPv6 : cfg . IPv6 ,
2018-12-05 13:13:29 +00:00
EnhancedMode : cfg . EnhancedMode ,
2019-09-15 05:36:45 +00:00
FallbackFilter : FallbackFilter {
2021-11-17 08:03:47 +00:00
IPCIDR : [ ] * net . IPNet { } ,
GeoSite : [ ] * router . DomainMatcher { } ,
2019-09-15 05:36:45 +00:00
} ,
2018-12-05 13:13:29 +00:00
}
2019-02-28 16:52:30 +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
}
2019-02-28 16:52:30 +00:00
if dnsCfg . Fallback , err = parseNameServer ( cfg . Fallback ) ; err != nil {
return nil , err
2018-12-05 13:13:29 +00:00
}
2021-05-19 03:17:35 +00:00
if dnsCfg . NameServerPolicy , err = parseNameServerPolicy ( cfg . NameServerPolicy ) ; err != nil {
return nil , err
}
2020-02-15 13:42:46 +00: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 14:13:15 +00:00
host , _ , err := net . SplitHostPort ( ns . Addr )
if err != nil || net . ParseIP ( host ) == nil {
2020-02-15 13:42:46 +00:00
return nil , errors . New ( "default nameserver should be pure IP" )
}
}
2021-10-18 13:08:27 +00:00
if cfg . EnhancedMode == C . DNSFakeIP {
2019-05-02 16:05:14 +00:00
_ , ipnet , err := net . ParseCIDR ( cfg . FakeIPRange )
if err != nil {
return nil , err
}
2019-12-27 16:10:06 +00:00
2020-05-28 04:13:05 +00:00
var host * trie . DomainTrie
2019-12-27 16:10:06 +00:00
// fake ip skip host filter
if len ( cfg . FakeIPFilter ) != 0 {
host = trie . New ( )
for _ , domain := range cfg . FakeIPFilter {
host . Insert ( domain , true )
2021-11-17 08:03:47 +00:00
}
}
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-04 16:33:42 +00:00
_ = 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 ,
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
}
2020-08-11 02:28:17 +00:00
if cfg . UseHosts {
dnsCfg . Hosts = hosts
}
2018-12-05 13:13:29 +00:00
return dnsCfg , nil
}
2019-06-27 09:04:25 +00:00
func parseAuthentication ( rawRecords [ ] string ) [ ] auth . AuthUser {
2022-03-16 04:10:13 +00:00
users := [ ] auth . AuthUser { }
2019-06-27 09:04:25 +00:00
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 } )
2019-06-27 09:04:25 +00:00
}
}
return users
}
2021-11-17 08:03:47 +00: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
}
2022-03-17 09:41:02 +00:00
2022-03-08 21:08:35 +00:00
func parseTun ( rawTun RawTun , general * General ) ( * Tun , error ) {
if ( rawTun . Enable || general . TProxyPort != 0 ) && general . Interface == "" {
autoDetectInterfaceName , err := commons . GetAutoDetectInterface ( )
if err != nil || autoDetectInterfaceName == "" {
return nil , fmt . Errorf ( "can not find auto detect interface: %w. you must be detect `interface-name` if tun set to enable or `tproxy-port` isn't zore" , err )
}
general . Interface = autoDetectInterfaceName
}
2022-03-11 18:16:13 +00:00
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
}
2022-03-14 18:55:06 +00:00
addrPort , err := netip . ParseAddrPort ( d )
2022-03-11 18:16:13 +00:00
if err != nil {
return nil , fmt . Errorf ( "parse dns-hijack url error: %w" , err )
2022-03-08 21:08:35 +00:00
}
2022-03-11 18:16:13 +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
}