2018-07-26 00:04:59 +08:00
package config
import (
2020-02-15 21:42:46 +08:00
"errors"
2018-07-26 00:04:59 +08:00
"fmt"
2018-12-05 21:13:29 +08:00
"net"
2022-03-12 02:16:13 +08:00
"net/netip"
2018-12-05 21:13:29 +08:00
"net/url"
2018-07-26 00:04:59 +08:00
"os"
2021-07-06 15:07:05 +08:00
"runtime"
2018-07-26 00:04:59 +08:00
"strings"
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"
2022-03-09 05:08:35 +08:00
"github.com/Dreamacro/clash/component/dialer"
2019-05-03 00:05:14 +08:00
"github.com/Dreamacro/clash/component/fakeip"
2022-02-23 02:38:50 +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"
2022-03-09 05:08:35 +08:00
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
2018-11-21 13:47:46 +08:00
"github.com/Dreamacro/clash/log"
2021-06-10 14:05:56 +08:00
R "github.com/Dreamacro/clash/rule"
2018-11-21 13:47:46 +08:00
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-17 14:23:47 +08:00
Mode T . TunnelMode ` json:"mode" `
LogLevel log . LogLevel ` json:"log-level" `
IPv6 bool ` json:"ipv6" `
Interface string ` json:"-" `
RoutingMark int ` json:"-" `
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 {
2022-02-23 02:38:50 +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-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-07-01 22:49:29 +08:00
// Tun config
type Tun struct {
2022-03-12 02:16:13 +08: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-07-01 22:49:29 +08:00
}
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
2018-07-26 00:04:59 +08:00
// Config is clash config manager
type Config struct {
2019-04-24 12:02:52 +08:00
General * General
2021-07-01 22:49:29 +08:00
Tun * Tun
2019-04-24 12:02:52 +08:00
DNS * DNS
Experimental * Experimental
2020-05-28 12:13:05 +08:00
Hosts * trie . DomainTrie
2021-02-18 23:41:50 +08:00
Profile * Profile
2019-04-24 12:02:52 +08:00
Rules [ ] C . Rule
2019-06-27 17:04:25 +08:00
Users [ ] auth . AuthUser
2019-04-24 12:02:52 +08:00
Proxies map [ string ] C . Proxy
2021-07-04 20:32:59 +08:00
Providers map [ string ] providerTypes . ProxyProvider
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" `
2022-02-23 02:38:50 +08:00
GeoSite [ ] string ` yaml:"geosite" `
2018-12-05 21:13:29 +08:00
}
2022-03-09 05:08:35 +08: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-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" `
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-17 14:23:47 +08:00
RoutingMark int ` yaml:"routing-mark" `
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" `
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" `
2022-03-09 05:08:35 +08:00
Tun RawTun ` 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" `
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 ,
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 { } { } ,
2022-03-09 05:08:35 +08:00
Tun : RawTun {
2021-07-01 22:49:29 +08:00
Enable : false ,
2022-03-09 05:08:35 +08:00
Device : "" ,
Stack : C . TunGvisor ,
DNSHijack : [ ] string { "0.0.0.0:53" } , // default hijack all dns query
2021-07-01 22:49:29 +08:00
AutoRoute : true ,
} ,
2020-01-11 00:22:34 +08:00
DNS : RawDNS {
2022-03-09 05:08:35 +08:00
Enable : false ,
UseHosts : true ,
EnhancedMode : C . DNSMapping ,
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 { } ,
2022-02-23 02:38:50 +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-07-01 22:49:29 +08:00
"223.5.5.5" ,
2020-02-15 21:42:46 +08:00
} ,
2022-03-09 05:08:35 +08:00
NameServer : [ ] string { // default if user not set
"https://doh.pub/dns-query" ,
"tls://223.5.5.5:853" ,
} ,
2018-12-05 21:52:31 +08:00
} ,
2021-02-18 23:41:50 +08:00
Profile : Profile {
StoreSelected : true ,
} ,
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
2018-07-26 00:04:59 +08:00
2022-03-09 05:08:35 +08: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 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
2019-06-20 11:03:50 +08:00
rules , 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
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
2022-02-23 02:38:50 +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
2018-07-26 00:04:59 +08:00
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-17 14:23:47 +08:00
Mode : cfg . Mode ,
LogLevel : cfg . LogLevel ,
IPv6 : cfg . IPv6 ,
Interface : cfg . Interface ,
RoutingMark : cfg . RoutingMark ,
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 )
2019-05-15 14:40:14 +08:00
proxyList := [ ] string { }
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 ( ) )
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 ( ) )
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 )
}
// 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
for _ , provider := range providersMap {
log . Infoln ( "Start initial provider %s" , provider . Name ( ) )
if err := provider . Initial ( ) ; err != nil {
2020-06-01 00:39:41 +08:00
return nil , nil , fmt . Errorf ( "initial proxy provider %s error: %w" , provider . Name ( ) , err )
2018-10-02 15:26:36 +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
}
2020-01-11 21:02:55 +08:00
// initial compatible provider
2019-12-10 17:27:07 +08:00
for _ , pd := range providersMap {
2021-07-04 20:32:59 +08:00
if pd . VehicleType ( ) != providerTypes . Compatible {
2019-12-10 17:27:07 +08:00
continue
}
log . Infoln ( "Start initial compatible provider %s" , pd . Name ( ) )
if err := pd . Initial ( ) ; err != nil {
return nil , nil , err
}
}
2019-02-15 14:25:20 +08:00
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 )
2019-12-08 12:17:24 +08:00
return proxies , providersMap , nil
2018-07-26 00:04:59 +08:00
}
2020-01-11 00:22:34 +08:00
func parseRules ( cfg * RawConfig , proxies map [ string ] C . Proxy ) ( [ ] C . Rule , error ) {
2018-07-26 00:04:59 +08:00
rules := [ ] C . Rule { }
2018-10-02 15:26:36 +08:00
rulesConfig := cfg . Rule
2020-03-07 20:01:24 +08:00
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-09-01 18:29:48 +08:00
payload string
target string
params = [ ] string { }
ruleName = strings . ToUpper ( rule [ 0 ] )
2018-11-21 18:21:24 +08:00
)
2019-10-28 00:02:23 +08:00
switch l := len ( rule ) ; {
case l == 2 :
2018-11-21 18:21:24 +08:00
target = rule [ 1 ]
2019-10-28 00:02:23 +08:00
case l == 3 :
2021-09-01 18:29:48 +08:00
if ruleName == "MATCH" {
payload = ""
target = rule [ 1 ]
params = rule [ 2 : ]
break
}
2018-11-21 18:21:24 +08:00
payload = rule [ 1 ]
target = rule [ 2 ]
2019-10-28 00:02:23 +08:00
case l >= 4 :
payload = rule [ 1 ]
target = rule [ 2 ]
params = rule [ 3 : ]
2018-11-21 18:21:24 +08:00
default :
2020-08-25 22:19:59 +08:00
return nil , fmt . Errorf ( "rules[%d] [%s] error: format invalid" , idx , line )
2018-07-26 00:04:59 +08:00
}
2018-11-21 18:21:24 +08:00
2019-06-20 11:03:50 +08:00
if _ , ok := proxies [ target ] ; ! ok {
2020-08-25 22:19:59 +08:00
return 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
2021-09-01 18:29:48 +08:00
parsed , parseErr := R . ParseRule ( ruleName , payload , target , params )
2019-10-28 00:02:23 +08:00
if parseErr != nil {
2020-08-25 22:19:59 +08:00
return nil , fmt . Errorf ( "rules[%d] [%s] error: %s" , idx , line , parseErr . Error ( ) )
2019-03-30 14:11:59 +08:00
}
rules = append ( rules , parsed )
2018-07-26 00:04:59 +08:00
}
2021-07-06 15:07:05 +08:00
runtime . GC ( )
2018-11-21 13:47:46 +08:00
return rules , 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 )
}
tree . Insert ( domain , ip )
}
}
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 ) {
nameservers := [ ] dns . NameServer { }
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
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 {
2022-02-23 02:38:50 +08:00
Net : dnsNetType ,
Addr : addr ,
ProxyAdapter : u . Fragment ,
2022-03-12 02:16:13 +08:00
Interface : dialer . DefaultInterface . Load ( ) ,
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 ) {
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
}
2022-02-23 02:38:50 +08:00
func parseFallbackGeoSite ( countries [ ] string , rules [ ] C . Rule ) ( [ ] * router . DomainMatcher , error ) {
sites := [ ] * router . DomainMatcher { }
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 {
2022-02-23 02:38:50 +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 {
host . Insert ( domain , true )
}
}
2022-02-23 02:38:50 +08:00
if len ( dnsCfg . Fallback ) != 0 {
if host == nil {
host = trie . New ( )
}
for _ , fb := range dnsCfg . Fallback {
if net . ParseIP ( fb . Addr ) != nil {
continue
}
host . Insert ( fb . Addr , true )
}
}
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
}
2022-02-23 02:38:50 +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
}
2022-03-09 05:08:35 +08: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-12 02:16:13 +08:00
var dnsHijack [ ] netip . AddrPort
2022-03-09 05:08:35 +08:00
for _ , dns := range rawTun . DNSHijack {
2022-03-12 02:16:13 +08:00
if _ , after , ok := strings . Cut ( dns , "://" ) ; ok {
dns = after
2022-03-09 05:08:35 +08:00
}
2022-03-12 02:16:13 +08:00
addrPort , err := netip . ParseAddrPort ( dns )
if err != nil {
return nil , fmt . Errorf ( "parse dns-hijack url error: %w" , err )
2022-03-09 05:08:35 +08:00
}
2022-03-12 02:16:13 +08:00
dnsHijack = append ( dnsHijack , addrPort )
2022-03-09 05:08:35 +08:00
}
return & Tun {
Enable : rawTun . Enable ,
Device : rawTun . Device ,
Stack : rawTun . Stack ,
DNSHijack : dnsHijack ,
AutoRoute : rawTun . AutoRoute ,
} , nil
}