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"
|
2023-01-28 16:09:14 +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"
|
2023-09-18 19:21:30 +08:00
|
|
|
"path"
|
2023-03-12 16:42:41 +08:00
|
|
|
"regexp"
|
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
|
|
|
|
2023-11-03 21:01:45 +08:00
|
|
|
"github.com/metacubex/mihomo/adapter"
|
|
|
|
"github.com/metacubex/mihomo/adapter/outbound"
|
|
|
|
"github.com/metacubex/mihomo/adapter/outboundgroup"
|
|
|
|
"github.com/metacubex/mihomo/adapter/provider"
|
|
|
|
N "github.com/metacubex/mihomo/common/net"
|
|
|
|
"github.com/metacubex/mihomo/common/utils"
|
|
|
|
"github.com/metacubex/mihomo/component/auth"
|
|
|
|
"github.com/metacubex/mihomo/component/fakeip"
|
|
|
|
"github.com/metacubex/mihomo/component/geodata"
|
|
|
|
"github.com/metacubex/mihomo/component/geodata/router"
|
|
|
|
P "github.com/metacubex/mihomo/component/process"
|
|
|
|
"github.com/metacubex/mihomo/component/resolver"
|
|
|
|
SNIFF "github.com/metacubex/mihomo/component/sniffer"
|
|
|
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
|
|
|
"github.com/metacubex/mihomo/component/trie"
|
|
|
|
C "github.com/metacubex/mihomo/constant"
|
2023-11-17 19:03:39 +08:00
|
|
|
"github.com/metacubex/mihomo/constant/features"
|
2023-11-03 21:01:45 +08:00
|
|
|
providerTypes "github.com/metacubex/mihomo/constant/provider"
|
|
|
|
snifferTypes "github.com/metacubex/mihomo/constant/sniffer"
|
|
|
|
"github.com/metacubex/mihomo/dns"
|
|
|
|
L "github.com/metacubex/mihomo/listener"
|
|
|
|
LC "github.com/metacubex/mihomo/listener/config"
|
|
|
|
"github.com/metacubex/mihomo/log"
|
|
|
|
R "github.com/metacubex/mihomo/rules"
|
|
|
|
RP "github.com/metacubex/mihomo/rules/provider"
|
|
|
|
T "github.com/metacubex/mihomo/tunnel"
|
2022-03-17 12:26:43 +08:00
|
|
|
|
2023-11-09 08:47:44 +08:00
|
|
|
orderedmap "github.com/wk8/go-ordered-map/v2"
|
2022-05-26 17:47:05 +08:00
|
|
|
"gopkg.in/yaml.v3"
|
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
|
2023-02-07 01:26:08 +08:00
|
|
|
Mode T.TunnelMode `json:"mode"`
|
|
|
|
UnifiedDelay bool
|
|
|
|
LogLevel log.LogLevel `json:"log-level"`
|
|
|
|
IPv6 bool `json:"ipv6"`
|
|
|
|
Interface string `json:"interface-name"`
|
|
|
|
RoutingMark int `json:"-"`
|
2023-08-06 23:34:10 +08:00
|
|
|
GeoXUrl GeoXUrl `json:"geox-url"`
|
2023-12-03 23:10:09 +08:00
|
|
|
GeoAutoUpdate bool `json:"geo-auto-update"`
|
|
|
|
GeoUpdateInterval int `json:"geo-update-interval"`
|
2023-02-07 01:26:08 +08:00
|
|
|
GeodataMode bool `json:"geodata-mode"`
|
|
|
|
GeodataLoader string `json:"geodata-loader"`
|
|
|
|
TCPConcurrent bool `json:"tcp-concurrent"`
|
|
|
|
FindProcessMode P.FindProcessMode `json:"find-process-mode"`
|
|
|
|
Sniffing bool `json:"sniffing"`
|
|
|
|
EBpf EBpf `json:"-"`
|
|
|
|
GlobalClientFingerprint string `json:"global-client-fingerprint"`
|
2023-09-07 18:44:58 +08:00
|
|
|
GlobalUA string `json:"global-ua"`
|
2020-06-18 18:11:02 +08:00
|
|
|
}
|
|
|
|
|
2022-03-15 02:55:06 +08:00
|
|
|
// Inbound config
|
2020-06-18 18:11:02 +08:00
|
|
|
type Inbound struct {
|
2023-10-10 19:43:26 +08:00
|
|
|
Port int `json:"port"`
|
|
|
|
SocksPort int `json:"socks-port"`
|
|
|
|
RedirPort int `json:"redir-port"`
|
|
|
|
TProxyPort int `json:"tproxy-port"`
|
|
|
|
MixedPort int `json:"mixed-port"`
|
|
|
|
Tun LC.Tun `json:"tun"`
|
|
|
|
TuicServer LC.TuicServer `json:"tuic-server"`
|
|
|
|
ShadowSocksConfig string `json:"ss-config"`
|
|
|
|
VmessConfig string `json:"vmess-config"`
|
|
|
|
Authentication []string `json:"authentication"`
|
|
|
|
SkipAuthPrefixes []netip.Prefix `json:"skip-auth-prefixes"`
|
|
|
|
AllowLan bool `json:"allow-lan"`
|
|
|
|
BindAddress string `json:"bind-address"`
|
|
|
|
InboundTfo bool `json:"inbound-tfo"`
|
|
|
|
InboundMPTCP bool `json:"inbound-mptcp"`
|
2020-06-18 18:11:02 +08:00
|
|
|
}
|
|
|
|
|
2022-03-15 02:55:06 +08:00
|
|
|
// Controller config
|
2020-06-18 18:11:02 +08:00
|
|
|
type Controller struct {
|
2022-12-03 14:14:15 +08:00
|
|
|
ExternalController string `json:"-"`
|
|
|
|
ExternalControllerTLS string `json:"-"`
|
|
|
|
ExternalUI string `json:"-"`
|
|
|
|
Secret string `json:"-"`
|
2018-08-12 02:23:46 +08:00
|
|
|
}
|
|
|
|
|
2023-09-01 03:11:35 +08:00
|
|
|
// NTP config
|
|
|
|
type NTP struct {
|
2023-09-03 17:48:52 +08:00
|
|
|
Enable bool `yaml:"enable"`
|
|
|
|
Server string `yaml:"server"`
|
|
|
|
Port int `yaml:"port"`
|
|
|
|
Interval int `yaml:"interval"`
|
2023-09-25 09:11:20 +08:00
|
|
|
DialerProxy string `yaml:"dialer-proxy"`
|
|
|
|
WriteToSystem bool `yaml:"write-to-system"`
|
2023-09-01 03:11:35 +08:00
|
|
|
}
|
|
|
|
|
2018-12-05 21:13:29 +08:00
|
|
|
// DNS config
|
|
|
|
type DNS struct {
|
2022-03-28 00:44:13 +08:00
|
|
|
Enable bool `yaml:"enable"`
|
2022-07-03 21:59:47 +08:00
|
|
|
PreferH3 bool `yaml:"prefer-h3"`
|
2022-03-28 00:44:13 +08:00
|
|
|
IPv6 bool `yaml:"ipv6"`
|
2023-03-10 23:38:16 +08:00
|
|
|
IPv6Timeout uint `yaml:"ipv6-timeout"`
|
2022-03-28 00:44:13 +08:00
|
|
|
NameServer []dns.NameServer `yaml:"nameserver"`
|
|
|
|
Fallback []dns.NameServer `yaml:"fallback"`
|
|
|
|
FallbackFilter FallbackFilter `yaml:"fallback-filter"`
|
|
|
|
Listen string `yaml:"listen"`
|
|
|
|
EnhancedMode C.DNSMode `yaml:"enhanced-mode"`
|
|
|
|
DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
|
2023-12-02 17:07:36 +08:00
|
|
|
CacheAlgorithm string `yaml:"cache-algorithm"`
|
2022-03-28 00:44:13 +08:00
|
|
|
FakeIPRange *fakeip.Pool
|
2023-03-12 15:00:59 +08:00
|
|
|
Hosts *trie.DomainTrie[resolver.HostValue]
|
2023-11-09 08:47:44 +08:00
|
|
|
NameServerPolicy *orderedmap.OrderedMap[string, []dns.NameServer]
|
2022-03-28 00:44:13 +08:00
|
|
|
ProxyServerNameserver []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"`
|
2023-10-26 10:39:54 +08:00
|
|
|
IPCIDR []netip.Prefix `yaml:"ipcidr"`
|
2021-11-17 16:03:47 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-12-03 14:14:15 +08:00
|
|
|
type TLS struct {
|
2023-02-25 22:01:20 +08:00
|
|
|
Certificate string `yaml:"certificate"`
|
|
|
|
PrivateKey string `yaml:"private-key"`
|
|
|
|
CustomTrustCert []string `yaml:"custom-certifactes"`
|
2022-12-03 14:14:15 +08:00
|
|
|
}
|
|
|
|
|
2022-03-22 05:38:42 +08:00
|
|
|
// IPTables config
|
|
|
|
type IPTables struct {
|
2022-03-23 11:04:43 +08:00
|
|
|
Enable bool `yaml:"enable" json:"enable"`
|
|
|
|
InboundInterface string `yaml:"inbound-interface" json:"inbound-interface"`
|
|
|
|
Bypass []string `yaml:"bypass" json:"bypass"`
|
2022-03-22 05:38:42 +08:00
|
|
|
}
|
|
|
|
|
2022-04-09 22:30:36 +08:00
|
|
|
type Sniffer struct {
|
2022-10-14 07:46:33 +08:00
|
|
|
Enable bool
|
2023-01-23 13:16:25 +08:00
|
|
|
Sniffers map[snifferTypes.Type]SNIFF.SnifferConfig
|
2023-04-01 11:53:39 +08:00
|
|
|
ForceDomain *trie.DomainSet
|
|
|
|
SkipDomain *trie.DomainSet
|
2022-10-14 07:46:33 +08:00
|
|
|
ForceDnsMapping bool
|
2022-10-14 08:42:28 +08:00
|
|
|
ParsePureIp bool
|
2022-04-09 22:30:36 +08:00
|
|
|
}
|
|
|
|
|
2019-04-24 12:02:52 +08:00
|
|
|
// Experimental config
|
2022-07-10 20:44:24 +08:00
|
|
|
type Experimental struct {
|
2023-09-08 22:58:59 +08:00
|
|
|
Fingerprints []string `yaml:"fingerprints"`
|
|
|
|
QUICGoDisableGSO bool `yaml:"quic-go-disable-gso"`
|
2023-10-01 09:10:11 +08:00
|
|
|
QUICGoDisableECN bool `yaml:"quic-go-disable-ecn"`
|
2022-07-10 20:44:24 +08:00
|
|
|
}
|
2019-04-24 12:02:52 +08:00
|
|
|
|
2023-11-03 21:01:45 +08:00
|
|
|
// Config is mihomo config manager
|
2018-07-26 00:04:59 +08:00
|
|
|
type Config struct {
|
2021-11-17 16:03:47 +08:00
|
|
|
General *General
|
2022-03-23 10:18:08 +08:00
|
|
|
IPTables *IPTables
|
2023-09-01 03:11:35 +08:00
|
|
|
NTP *NTP
|
2021-11-17 16:03:47 +08:00
|
|
|
DNS *DNS
|
|
|
|
Experimental *Experimental
|
2023-03-12 15:00:59 +08:00
|
|
|
Hosts *trie.DomainTrie[resolver.HostValue]
|
2021-11-17 16:03:47 +08:00
|
|
|
Profile *Profile
|
|
|
|
Rules []C.Rule
|
2022-12-04 13:37:14 +08:00
|
|
|
SubRules map[string][]C.Rule
|
2021-11-17 16:03:47 +08:00
|
|
|
Users []auth.AuthUser
|
|
|
|
Proxies map[string]C.Proxy
|
2022-12-04 21:53:13 +08:00
|
|
|
Listeners map[string]C.InboundListener
|
2021-11-17 16:03:47 +08:00
|
|
|
Providers map[string]providerTypes.ProxyProvider
|
2022-04-28 08:55:45 +08:00
|
|
|
RuleProviders map[string]providerTypes.RuleProvider
|
2022-12-06 10:13:05 +08:00
|
|
|
Tunnels []LC.Tunnel
|
2022-04-09 22:30:36 +08:00
|
|
|
Sniffer *Sniffer
|
2022-12-03 14:14:15 +08:00
|
|
|
TLS *TLS
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
|
|
|
|
2023-09-01 03:11:35 +08:00
|
|
|
type RawNTP struct {
|
2023-09-03 17:48:52 +08:00
|
|
|
Enable bool `yaml:"enable"`
|
|
|
|
Server string `yaml:"server"`
|
|
|
|
ServerPort int `yaml:"server-port"`
|
|
|
|
Interval int `yaml:"interval"`
|
2023-09-25 09:11:20 +08:00
|
|
|
DialerProxy string `yaml:"dialer-proxy"`
|
|
|
|
WriteToSystem bool `yaml:"write-to-system"`
|
2023-09-01 03:11:35 +08:00
|
|
|
}
|
|
|
|
|
2020-01-11 00:22:34 +08:00
|
|
|
type RawDNS struct {
|
2023-11-17 19:03:39 +08:00
|
|
|
Enable bool `yaml:"enable" json:"enable"`
|
|
|
|
PreferH3 bool `yaml:"prefer-h3" json:"prefer-h3"`
|
|
|
|
IPv6 bool `yaml:"ipv6" json:"ipv6"`
|
|
|
|
IPv6Timeout uint `yaml:"ipv6-timeout" json:"ipv6-timeout"`
|
|
|
|
UseHosts bool `yaml:"use-hosts" json:"use-hosts"`
|
|
|
|
NameServer []string `yaml:"nameserver" json:"nameserver"`
|
|
|
|
Fallback []string `yaml:"fallback" json:"fallback"`
|
|
|
|
FallbackFilter RawFallbackFilter `yaml:"fallback-filter" json:"fallback-filter"`
|
|
|
|
Listen string `yaml:"listen" json:"listen"`
|
|
|
|
EnhancedMode C.DNSMode `yaml:"enhanced-mode" json:"enhanced-mode"`
|
|
|
|
FakeIPRange string `yaml:"fake-ip-range" json:"fake-ip-range"`
|
|
|
|
FakeIPFilter []string `yaml:"fake-ip-filter" json:"fake-ip-filter"`
|
|
|
|
DefaultNameserver []string `yaml:"default-nameserver" json:"default-nameserver"`
|
2023-12-02 17:07:36 +08:00
|
|
|
CacheAlgorithm string `yaml:"cache-algorithm" json:"cache-algorithm"`
|
2023-11-17 19:03:39 +08:00
|
|
|
NameServerPolicy *orderedmap.OrderedMap[string, any] `yaml:"nameserver-policy" json:"nameserver-policy"`
|
|
|
|
ProxyServerNameserver []string `yaml:"proxy-server-nameserver" json:"proxy-server-nameserver"`
|
2019-09-15 13:36:45 +08:00
|
|
|
}
|
|
|
|
|
2020-01-11 00:22:34 +08:00
|
|
|
type RawFallbackFilter struct {
|
2023-11-17 01:19:20 +08:00
|
|
|
GeoIP bool `yaml:"geoip" json:"geoip"`
|
|
|
|
GeoIPCode string `yaml:"geoip-code" json:"geoip-code"`
|
|
|
|
IPCIDR []string `yaml:"ipcidr" json:"ipcidr"`
|
|
|
|
Domain []string `yaml:"domain" json:"domain"`
|
|
|
|
GeoSite []string `yaml:"geosite" json:"geosite"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type RawClashForAndroid struct {
|
|
|
|
AppendSystemDNS bool `yaml:"append-system-dns" json:"append-system-dns"`
|
|
|
|
UiSubtitlePattern string `yaml:"ui-subtitle-pattern" json:"ui-subtitle-pattern"`
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
2022-03-09 05:08:35 +08:00
|
|
|
type RawTun struct {
|
2022-10-10 19:02:57 +08:00
|
|
|
Enable bool `yaml:"enable" json:"enable"`
|
|
|
|
Device string `yaml:"device" json:"device"`
|
|
|
|
Stack C.TUNStack `yaml:"stack" json:"stack"`
|
|
|
|
DNSHijack []string `yaml:"dns-hijack" json:"dns-hijack"`
|
|
|
|
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
|
|
|
|
AutoDetectInterface bool `yaml:"auto-detect-interface"`
|
|
|
|
RedirectToTun []string `yaml:"-" json:"-"`
|
2022-10-06 22:18:49 +08:00
|
|
|
|
|
|
|
MTU uint32 `yaml:"mtu" json:"mtu,omitempty"`
|
2023-10-10 19:49:16 +08:00
|
|
|
//Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4_address,omitempty"`
|
2023-11-02 11:37:40 +08:00
|
|
|
Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"`
|
|
|
|
StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"`
|
|
|
|
Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4_route_address,omitempty"`
|
|
|
|
Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6_route_address,omitempty"`
|
|
|
|
Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4_route_exclude_address,omitempty"`
|
|
|
|
Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6_route_exclude_address,omitempty"`
|
|
|
|
IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"`
|
|
|
|
IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"`
|
|
|
|
ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"`
|
|
|
|
ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"`
|
|
|
|
IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"`
|
|
|
|
IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"`
|
|
|
|
ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"`
|
|
|
|
EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"`
|
|
|
|
UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"`
|
|
|
|
FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"`
|
2022-03-09 05:08:35 +08:00
|
|
|
}
|
|
|
|
|
2022-11-28 17:09:25 +08:00
|
|
|
type RawTuicServer struct {
|
2023-06-12 17:44:22 +08:00
|
|
|
Enable bool `yaml:"enable" json:"enable"`
|
|
|
|
Listen string `yaml:"listen" json:"listen"`
|
|
|
|
Token []string `yaml:"token" json:"token"`
|
|
|
|
Users map[string]string `yaml:"users" json:"users,omitempty"`
|
|
|
|
Certificate string `yaml:"certificate" json:"certificate"`
|
|
|
|
PrivateKey string `yaml:"private-key" json:"private-key"`
|
|
|
|
CongestionController string `yaml:"congestion-controller" json:"congestion-controller,omitempty"`
|
|
|
|
MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"`
|
|
|
|
AuthenticationTimeout int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"`
|
|
|
|
ALPN []string `yaml:"alpn" json:"alpn,omitempty"`
|
|
|
|
MaxUdpRelayPacketSize int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"`
|
2023-06-21 14:00:49 +08:00
|
|
|
CWND int `yaml:"cwnd" json:"cwnd,omitempty"`
|
2022-11-28 17:09:25 +08:00
|
|
|
}
|
|
|
|
|
2020-01-11 00:22:34 +08:00
|
|
|
type RawConfig struct {
|
2023-11-17 19:03:39 +08:00
|
|
|
Port int `yaml:"port" json:"port"`
|
|
|
|
SocksPort int `yaml:"socks-port" json:"socks-port"`
|
|
|
|
RedirPort int `yaml:"redir-port" json:"redir-port"`
|
|
|
|
TProxyPort int `yaml:"tproxy-port" json:"tproxy-port"`
|
|
|
|
MixedPort int `yaml:"mixed-port" json:"mixed-port"`
|
2023-02-07 01:26:08 +08:00
|
|
|
ShadowSocksConfig string `yaml:"ss-config"`
|
|
|
|
VmessConfig string `yaml:"vmess-config"`
|
|
|
|
InboundTfo bool `yaml:"inbound-tfo"`
|
2023-08-09 17:09:03 +08:00
|
|
|
InboundMPTCP bool `yaml:"inbound-mptcp"`
|
2023-11-17 19:03:39 +08:00
|
|
|
Authentication []string `yaml:"authentication" json:"authentication"`
|
2023-10-10 19:43:26 +08:00
|
|
|
SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes"`
|
2023-11-17 19:03:39 +08:00
|
|
|
AllowLan bool `yaml:"allow-lan" json:"allow-lan"`
|
|
|
|
BindAddress string `yaml:"bind-address" json:"bind-address"`
|
|
|
|
Mode T.TunnelMode `yaml:"mode" json:"mode"`
|
|
|
|
UnifiedDelay bool `yaml:"unified-delay" json:"unified-delay"`
|
|
|
|
LogLevel log.LogLevel `yaml:"log-level" json:"log-level"`
|
|
|
|
IPv6 bool `yaml:"ipv6" json:"ipv6"`
|
2023-02-07 01:26:08 +08:00
|
|
|
ExternalController string `yaml:"external-controller"`
|
|
|
|
ExternalControllerTLS string `yaml:"external-controller-tls"`
|
|
|
|
ExternalUI string `yaml:"external-ui"`
|
2023-09-18 19:21:30 +08:00
|
|
|
ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"`
|
|
|
|
ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"`
|
2023-02-07 01:26:08 +08:00
|
|
|
Secret string `yaml:"secret"`
|
|
|
|
Interface string `yaml:"interface-name"`
|
|
|
|
RoutingMark int `yaml:"routing-mark"`
|
|
|
|
Tunnels []LC.Tunnel `yaml:"tunnels"`
|
2023-12-03 23:10:09 +08:00
|
|
|
GeoAutoUpdate bool `yaml:"geo-auto-update" json:"geo-auto-update"`
|
|
|
|
GeoUpdateInterval int `yaml:"geo-update-interval" json:"geo-update-interval"`
|
2023-11-17 19:03:39 +08:00
|
|
|
GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"`
|
|
|
|
GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"`
|
2023-02-07 01:26:08 +08:00
|
|
|
TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"`
|
|
|
|
FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"`
|
|
|
|
GlobalClientFingerprint string `yaml:"global-client-fingerprint"`
|
2023-09-07 18:44:58 +08:00
|
|
|
GlobalUA string `yaml:"global-ua"`
|
2023-09-02 16:25:55 +08:00
|
|
|
KeepAliveInterval int `yaml:"keep-alive-interval"`
|
2018-12-05 21:13:29 +08:00
|
|
|
|
2023-11-17 19:03:39 +08:00
|
|
|
Sniffer RawSniffer `yaml:"sniffer" json:"sniffer"`
|
2022-03-16 12:10:13 +08:00
|
|
|
ProxyProvider map[string]map[string]any `yaml:"proxy-providers"`
|
2022-03-17 17:41:02 +08:00
|
|
|
RuleProvider map[string]map[string]any `yaml:"rule-providers"`
|
2023-11-17 19:03:39 +08:00
|
|
|
Hosts map[string]any `yaml:"hosts" json:"hosts"`
|
|
|
|
NTP RawNTP `yaml:"ntp" json:"ntp"`
|
|
|
|
DNS RawDNS `yaml:"dns" json:"dns"`
|
2022-03-16 20:16:30 +08:00
|
|
|
Tun RawTun `yaml:"tun"`
|
2022-11-28 17:09:25 +08:00
|
|
|
TuicServer RawTuicServer `yaml:"tuic-server"`
|
2022-07-29 09:08:35 +08:00
|
|
|
EBpf EBpf `yaml:"ebpf"`
|
2022-03-22 05:38:42 +08:00
|
|
|
IPTables IPTables `yaml:"iptables"`
|
2022-03-16 12:10:13 +08:00
|
|
|
Experimental Experimental `yaml:"experimental"`
|
|
|
|
Profile Profile `yaml:"profile"`
|
2023-08-06 23:34:10 +08:00
|
|
|
GeoXUrl GeoXUrl `yaml:"geox-url"`
|
2022-03-16 12:10:13 +08:00
|
|
|
Proxy []map[string]any `yaml:"proxies"`
|
|
|
|
ProxyGroup []map[string]any `yaml:"proxy-groups"`
|
|
|
|
Rule []string `yaml:"rules"`
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
SubRules map[string][]string `yaml:"sub-rules"`
|
2022-12-04 13:37:14 +08:00
|
|
|
RawTLS TLS `yaml:"tls"`
|
|
|
|
Listeners []map[string]any `yaml:"listeners"`
|
2023-11-17 01:19:20 +08:00
|
|
|
|
2023-11-17 23:12:10 +08:00
|
|
|
ClashForAndroid RawClashForAndroid `yaml:"clash-for-android" json:"clash-for-android"`
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
2023-08-06 23:34:10 +08:00
|
|
|
type GeoXUrl struct {
|
2022-05-24 15:04:13 +08:00
|
|
|
GeoIp string `yaml:"geoip" json:"geoip"`
|
|
|
|
Mmdb string `yaml:"mmdb" json:"mmdb"`
|
|
|
|
GeoSite string `yaml:"geosite" json:"geosite"`
|
|
|
|
}
|
|
|
|
|
2022-05-16 17:29:08 +08:00
|
|
|
type RawSniffer struct {
|
2023-01-23 13:16:25 +08:00
|
|
|
Enable bool `yaml:"enable" json:"enable"`
|
2023-01-23 14:08:11 +08:00
|
|
|
OverrideDest bool `yaml:"override-destination" json:"override-destination"`
|
2023-01-23 13:16:25 +08:00
|
|
|
Sniffing []string `yaml:"sniffing" json:"sniffing"`
|
|
|
|
ForceDomain []string `yaml:"force-domain" json:"force-domain"`
|
|
|
|
SkipDomain []string `yaml:"skip-domain" json:"skip-domain"`
|
|
|
|
Ports []string `yaml:"port-whitelist" json:"port-whitelist"`
|
|
|
|
ForceDnsMapping bool `yaml:"force-dns-mapping" json:"force-dns-mapping"`
|
|
|
|
ParsePureIp bool `yaml:"parse-pure-ip" json:"parse-pure-ip"`
|
|
|
|
Sniff map[string]RawSniffingConfig `yaml:"sniff" json:"sniff"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type RawSniffingConfig struct {
|
2023-01-23 14:08:11 +08:00
|
|
|
Ports []string `yaml:"ports" json:"ports"`
|
|
|
|
OverrideDest *bool `yaml:"override-destination" json:"override-destination"`
|
2022-04-09 22:30:36 +08:00
|
|
|
}
|
|
|
|
|
2022-07-29 09:08:35 +08:00
|
|
|
// EBpf config
|
|
|
|
type EBpf struct {
|
|
|
|
RedirectToTun []string `yaml:"redirect-to-tun" json:"redirect-to-tun"`
|
|
|
|
AutoRedir []string `yaml:"auto-redir" json:"auto-redir"`
|
|
|
|
}
|
|
|
|
|
2022-07-04 18:53:24 +08:00
|
|
|
var (
|
|
|
|
GroupsList = list.New()
|
|
|
|
ProxiesList = list.New()
|
|
|
|
ParsingProxiesCallback func(groupsList *list.List, proxiesList *list.List)
|
|
|
|
)
|
|
|
|
|
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{
|
2023-12-03 23:10:09 +08:00
|
|
|
AllowLan: false,
|
|
|
|
BindAddress: "*",
|
|
|
|
IPv6: true,
|
|
|
|
Mode: T.Rule,
|
|
|
|
GeoAutoUpdate: false,
|
|
|
|
GeoUpdateInterval: 24,
|
|
|
|
GeodataMode: C.GeodataMode,
|
|
|
|
GeodataLoader: "memconservative",
|
|
|
|
UnifiedDelay: false,
|
|
|
|
Authentication: []string{},
|
|
|
|
LogLevel: log.INFO,
|
|
|
|
Hosts: map[string]any{},
|
|
|
|
Rule: []string{},
|
|
|
|
Proxy: []map[string]any{},
|
|
|
|
ProxyGroup: []map[string]any{},
|
|
|
|
TCPConcurrent: false,
|
|
|
|
FindProcessMode: P.FindProcessStrict,
|
|
|
|
GlobalUA: "clash.meta",
|
2022-03-17 17:41:02 +08:00
|
|
|
Tun: RawTun{
|
2022-04-07 21:36:19 +08:00
|
|
|
Enable: false,
|
|
|
|
Device: "",
|
2022-10-10 19:02:57 +08:00
|
|
|
Stack: C.TunGvisor,
|
2022-04-07 21:36:19 +08:00
|
|
|
DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query
|
2022-10-07 16:54:08 +08:00
|
|
|
AutoRoute: true,
|
|
|
|
AutoDetectInterface: true,
|
2023-10-10 19:49:16 +08:00
|
|
|
Inet6Address: []netip.Prefix{netip.MustParsePrefix("fdfe:dcba:9876::1/126")},
|
2022-03-17 17:41:02 +08:00
|
|
|
},
|
2022-11-28 17:09:25 +08:00
|
|
|
TuicServer: RawTuicServer{
|
|
|
|
Enable: false,
|
|
|
|
Token: nil,
|
2023-06-12 17:44:22 +08:00
|
|
|
Users: nil,
|
2022-11-28 17:09:25 +08:00
|
|
|
Certificate: "",
|
|
|
|
PrivateKey: "",
|
|
|
|
Listen: "",
|
|
|
|
CongestionController: "",
|
|
|
|
MaxIdleTime: 15000,
|
|
|
|
AuthenticationTimeout: 1000,
|
|
|
|
ALPN: []string{"h3"},
|
|
|
|
MaxUdpRelayPacketSize: 1500,
|
|
|
|
},
|
2022-08-22 23:17:41 +08:00
|
|
|
EBpf: EBpf{
|
|
|
|
RedirectToTun: []string{},
|
|
|
|
AutoRedir: []string{},
|
|
|
|
},
|
2022-03-22 05:38:42 +08:00
|
|
|
IPTables: IPTables{
|
|
|
|
Enable: false,
|
|
|
|
InboundInterface: "lo",
|
2022-03-23 11:04:43 +08:00
|
|
|
Bypass: []string{},
|
2022-03-22 05:38:42 +08:00
|
|
|
},
|
2023-09-03 17:48:52 +08:00
|
|
|
NTP: RawNTP{
|
|
|
|
Enable: false,
|
|
|
|
WriteToSystem: false,
|
|
|
|
Server: "time.apple.com",
|
|
|
|
ServerPort: 123,
|
|
|
|
Interval: 30,
|
|
|
|
},
|
2020-01-11 00:22:34 +08:00
|
|
|
DNS: RawDNS{
|
2022-03-09 05:08:35 +08:00
|
|
|
Enable: false,
|
2022-06-14 12:35:24 +08:00
|
|
|
IPv6: false,
|
2022-03-09 05:08:35 +08:00
|
|
|
UseHosts: true,
|
2023-03-10 23:38:16 +08:00
|
|
|
IPv6Timeout: 100,
|
2022-03-09 05:08:35 +08:00
|
|
|
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{},
|
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-03-09 05:08:35 +08:00
|
|
|
"https://doh.pub/dns-query",
|
|
|
|
"tls://223.5.5.5:853",
|
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
|
|
|
},
|
2022-05-16 17:29:08 +08:00
|
|
|
Sniffer: RawSniffer{
|
2022-10-14 07:46:33 +08:00
|
|
|
Enable: false,
|
|
|
|
Sniffing: []string{},
|
|
|
|
ForceDomain: []string{},
|
|
|
|
SkipDomain: []string{},
|
|
|
|
Ports: []string{},
|
|
|
|
ForceDnsMapping: true,
|
2022-10-14 08:42:28 +08:00
|
|
|
ParsePureIp: true,
|
2023-02-06 17:48:49 +08:00
|
|
|
OverrideDest: true,
|
2022-04-09 22:30:36 +08:00
|
|
|
},
|
2021-02-18 23:41:50 +08:00
|
|
|
Profile: Profile{
|
|
|
|
StoreSelected: true,
|
|
|
|
},
|
2023-08-06 23:34:10 +08:00
|
|
|
GeoXUrl: GeoXUrl{
|
2023-10-30 19:46:56 +08:00
|
|
|
Mmdb: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb",
|
|
|
|
GeoIp: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat",
|
|
|
|
GeoSite: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat",
|
2022-05-24 15:04:13 +08:00
|
|
|
},
|
2023-09-24 19:00:51 +08:00
|
|
|
ExternalUIURL: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip",
|
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{}
|
2022-02-06 01:59:35 +08:00
|
|
|
log.Infoln("Start initial configuration in progress") //Segment finished in xxm
|
|
|
|
startTime := time.Now()
|
2019-04-24 12:02:52 +08:00
|
|
|
config.Experimental = &rawCfg.Experimental
|
2021-02-18 23:41:50 +08:00
|
|
|
config.Profile = &rawCfg.Profile
|
2022-03-22 05:38:42 +08:00
|
|
|
config.IPTables = &rawCfg.IPTables
|
2022-12-04 13:37:14 +08:00
|
|
|
config.TLS = &rawCfg.RawTLS
|
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
|
|
|
|
2023-03-12 13:35:59 +08:00
|
|
|
if len(config.General.GlobalClientFingerprint) != 0 {
|
2023-08-06 23:34:10 +08:00
|
|
|
log.Debugln("GlobalClientFingerprint: %s", config.General.GlobalClientFingerprint)
|
2023-03-12 13:35:59 +08:00
|
|
|
tlsC.SetGlobalUtlsClient(config.General.GlobalClientFingerprint)
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2022-12-04 13:37:14 +08:00
|
|
|
listener, err := parseListeners(rawCfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
config.Listeners = listener
|
|
|
|
|
2022-12-05 22:29:52 +08:00
|
|
|
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
|
|
|
|
ruleProviders, err := parseRuleProviders(rawCfg)
|
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
|
|
|
}
|
2021-11-17 16:03:47 +08:00
|
|
|
config.RuleProviders = ruleProviders
|
2018-07-26 00:04:59 +08:00
|
|
|
|
2022-12-05 22:29:52 +08:00
|
|
|
subRules, err := parseSubRules(rawCfg, proxies)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
config.SubRules = subRules
|
|
|
|
|
|
|
|
rules, err := parseRules(rawCfg.Rule, proxies, subRules, "rules")
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
config.Rules = rules
|
|
|
|
|
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
|
|
|
|
2023-09-01 03:11:35 +08:00
|
|
|
ntpCfg := paresNTP(rawCfg)
|
|
|
|
config.NTP = ntpCfg
|
|
|
|
|
2023-04-01 11:53:39 +08:00
|
|
|
dnsCfg, err := parseDNS(rawCfg, hosts, rules, ruleProviders)
|
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
|
|
|
|
2022-11-10 21:08:06 +08:00
|
|
|
err = parseTun(rawCfg.Tun, config.General)
|
2023-11-17 23:12:10 +08:00
|
|
|
if !features.CMFA && err != nil {
|
2022-05-19 19:19:19 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-11-28 17:09:25 +08:00
|
|
|
err = parseTuicServer(rawCfg.TuicServer, config.General)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-06-27 17:04:25 +08:00
|
|
|
config.Users = parseAuthentication(rawCfg.Authentication)
|
2020-01-11 00:22:34 +08:00
|
|
|
|
2022-11-18 22:57:33 +08:00
|
|
|
config.Tunnels = rawCfg.Tunnels
|
|
|
|
// verify tunnels
|
|
|
|
for _, t := range config.Tunnels {
|
2022-11-28 20:31:32 +08:00
|
|
|
if len(t.Proxy) > 0 {
|
|
|
|
if _, ok := config.Proxies[t.Proxy]; !ok {
|
|
|
|
return nil, fmt.Errorf("tunnel proxy %s not found", t.Proxy)
|
|
|
|
}
|
2022-11-18 22:57:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 22:30:36 +08:00
|
|
|
config.Sniffer, err = parseSniffer(rawCfg.Sniffer)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-02-06 01:59:35 +08:00
|
|
|
elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms
|
|
|
|
log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) //Segment finished in xxm
|
2022-11-28 20:04:56 +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) {
|
2022-02-05 02:42:49 +08:00
|
|
|
geodata.SetLoader(cfg.GeodataLoader)
|
2023-12-03 23:10:09 +08:00
|
|
|
C.GeoAutoUpdate = cfg.GeoAutoUpdate
|
|
|
|
C.GeoUpdateInterval = cfg.GeoUpdateInterval
|
2023-08-06 23:34:10 +08:00
|
|
|
C.GeoIpUrl = cfg.GeoXUrl.GeoIp
|
|
|
|
C.GeoSiteUrl = cfg.GeoXUrl.GeoSite
|
|
|
|
C.MmdbUrl = cfg.GeoXUrl.Mmdb
|
2023-08-07 01:43:23 +08:00
|
|
|
C.GeodataMode = cfg.GeodataMode
|
2023-09-07 18:44:58 +08:00
|
|
|
C.UA = cfg.GlobalUA
|
2023-09-03 20:42:54 +08:00
|
|
|
if cfg.KeepAliveInterval != 0 {
|
|
|
|
N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second
|
2023-09-02 16:25:55 +08:00
|
|
|
}
|
2023-09-03 20:42:54 +08:00
|
|
|
|
2023-09-18 19:21:30 +08:00
|
|
|
ExternalUIPath = cfg.ExternalUI
|
2020-06-18 18:11:02 +08:00
|
|
|
// checkout externalUI exist
|
2023-09-18 19:21:30 +08:00
|
|
|
if ExternalUIPath != "" {
|
|
|
|
ExternalUIPath = C.Path.Resolve(ExternalUIPath)
|
|
|
|
if _, err := os.Stat(ExternalUIPath); os.IsNotExist(err) {
|
|
|
|
defaultUIpath := path.Join(C.Path.HomeDir(), "ui")
|
|
|
|
log.Warnln("external-ui: %s does not exist, creating folder in %s", ExternalUIPath, defaultUIpath)
|
|
|
|
if err := os.MkdirAll(defaultUIpath, os.ModePerm); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
ExternalUIPath = defaultUIpath
|
|
|
|
cfg.ExternalUI = defaultUIpath
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// checkout UIpath/name exist
|
|
|
|
if cfg.ExternalUIName != "" {
|
|
|
|
ExternalUIName = cfg.ExternalUIName
|
2023-09-20 14:23:58 +08:00
|
|
|
} else {
|
|
|
|
ExternalUIFolder = ExternalUIPath
|
2018-12-20 01:29:13 +08:00
|
|
|
}
|
2023-09-23 17:59:59 +08:00
|
|
|
if cfg.ExternalUIURL != "" {
|
|
|
|
ExternalUIURL = cfg.ExternalUIURL
|
|
|
|
}
|
2023-09-18 19:21:30 +08:00
|
|
|
|
2022-07-29 09:08:35 +08:00
|
|
|
cfg.Tun.RedirectToTun = cfg.EBpf.RedirectToTun
|
2020-06-18 18:11:02 +08:00
|
|
|
return &General{
|
|
|
|
Inbound: Inbound{
|
2022-11-11 20:56:08 +08:00
|
|
|
Port: cfg.Port,
|
|
|
|
SocksPort: cfg.SocksPort,
|
|
|
|
RedirPort: cfg.RedirPort,
|
|
|
|
TProxyPort: cfg.TProxyPort,
|
|
|
|
MixedPort: cfg.MixedPort,
|
|
|
|
ShadowSocksConfig: cfg.ShadowSocksConfig,
|
|
|
|
VmessConfig: cfg.VmessConfig,
|
|
|
|
AllowLan: cfg.AllowLan,
|
2023-10-10 19:43:26 +08:00
|
|
|
SkipAuthPrefixes: cfg.SkipAuthPrefixes,
|
2022-11-11 20:56:08 +08:00
|
|
|
BindAddress: cfg.BindAddress,
|
|
|
|
InboundTfo: cfg.InboundTfo,
|
2023-08-09 17:09:03 +08:00
|
|
|
InboundMPTCP: cfg.InboundMPTCP,
|
2020-06-18 18:11:02 +08:00
|
|
|
},
|
|
|
|
Controller: Controller{
|
2022-12-04 13:37:14 +08:00
|
|
|
ExternalController: cfg.ExternalController,
|
|
|
|
ExternalUI: cfg.ExternalUI,
|
|
|
|
Secret: cfg.Secret,
|
2022-12-03 14:14:15 +08:00
|
|
|
ExternalControllerTLS: cfg.ExternalControllerTLS,
|
2020-06-18 18:11:02 +08:00
|
|
|
},
|
2023-02-07 01:26:08 +08:00
|
|
|
UnifiedDelay: cfg.UnifiedDelay,
|
|
|
|
Mode: cfg.Mode,
|
|
|
|
LogLevel: cfg.LogLevel,
|
|
|
|
IPv6: cfg.IPv6,
|
|
|
|
Interface: cfg.Interface,
|
|
|
|
RoutingMark: cfg.RoutingMark,
|
2023-08-06 23:34:10 +08:00
|
|
|
GeoXUrl: cfg.GeoXUrl,
|
2023-12-03 23:10:09 +08:00
|
|
|
GeoAutoUpdate: cfg.GeoAutoUpdate,
|
|
|
|
GeoUpdateInterval: cfg.GeoUpdateInterval,
|
2023-02-07 01:26:08 +08:00
|
|
|
GeodataMode: cfg.GeodataMode,
|
|
|
|
GeodataLoader: cfg.GeodataLoader,
|
|
|
|
TCPConcurrent: cfg.TCPConcurrent,
|
|
|
|
FindProcessMode: cfg.FindProcessMode,
|
|
|
|
EBpf: cfg.EBpf,
|
|
|
|
GlobalClientFingerprint: cfg.GlobalClientFingerprint,
|
2023-09-07 18:44:58 +08:00
|
|
|
GlobalUA: cfg.GlobalUA,
|
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)
|
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
|
|
|
|
2022-03-15 02:55:06 +08:00
|
|
|
var proxyList []string
|
2022-05-16 17:29:08 +08:00
|
|
|
proxiesList := list.New()
|
|
|
|
groupsList := list.New()
|
2022-03-15 02:55:06 +08:00
|
|
|
|
2021-06-10 14:05:56 +08:00
|
|
|
proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect())
|
|
|
|
proxies["REJECT"] = adapter.NewProxy(outbound.NewReject())
|
2023-11-18 13:17:15 +08:00
|
|
|
proxies["REJECT-DROP"] = adapter.NewProxy(outbound.NewRejectDrop())
|
2022-01-18 21:09:36 +08:00
|
|
|
proxies["COMPATIBLE"] = adapter.NewProxy(outbound.NewCompatible())
|
2022-03-27 23:44:51 +08:00
|
|
|
proxies["PASS"] = adapter.NewProxy(outbound.NewPass())
|
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())
|
2022-05-16 17:29:08 +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)
|
2022-05-16 17:29:08 +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-03-15 02:55:06 +08:00
|
|
|
var ps []C.Proxy
|
2019-05-15 14:40:14 +08:00
|
|
|
for _, v := range proxyList {
|
2022-03-27 23:44:51 +08:00
|
|
|
if proxies[v].Type() == C.Pass {
|
|
|
|
continue
|
|
|
|
}
|
2019-05-15 14:40:14 +08:00
|
|
|
ps = append(ps, proxies[v])
|
2018-10-18 23:24:04 +08:00
|
|
|
}
|
2023-06-04 14:00:24 +08:00
|
|
|
hc := provider.NewHealthCheck(ps, "", 0, true, nil)
|
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)
|
2022-07-04 18:53:24 +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
|
|
|
}
|
|
|
|
|
2022-12-04 21:53:13 +08:00
|
|
|
func parseListeners(cfg *RawConfig) (listeners map[string]C.InboundListener, err error) {
|
|
|
|
listeners = make(map[string]C.InboundListener)
|
2022-12-04 13:37:14 +08:00
|
|
|
for index, mapping := range cfg.Listeners {
|
|
|
|
listener, err := L.ParseListener(mapping)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("proxy %d: %w", index, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, exist := mapping[listener.Name()]; exist {
|
|
|
|
return nil, fmt.Errorf("listener %s is the duplicate name", listener.Name())
|
|
|
|
}
|
|
|
|
|
|
|
|
listeners[listener.Name()] = listener
|
|
|
|
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-12-05 22:29:52 +08:00
|
|
|
func parseRuleProviders(cfg *RawConfig) (ruleProviders map[string]providerTypes.RuleProvider, err error) {
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
ruleProviders = map[string]providerTypes.RuleProvider{}
|
2021-12-02 22:56:17 +08:00
|
|
|
// parse rule provider
|
|
|
|
for name, mapping := range cfg.RuleProvider {
|
2022-06-10 13:36:09 +08:00
|
|
|
rp, err := RP.ParseRuleProvider(name, mapping, R.ParseRule)
|
2021-12-02 22:56:17 +08:00
|
|
|
if err != nil {
|
2022-12-05 22:29:52 +08:00
|
|
|
return nil, err
|
2021-12-02 22:56:17 +08:00
|
|
|
}
|
|
|
|
|
2022-04-28 08:55:45 +08:00
|
|
|
ruleProviders[name] = rp
|
2022-01-22 22:10:45 +08:00
|
|
|
RP.SetRuleProvider(rp)
|
2021-12-02 22:56:17 +08:00
|
|
|
}
|
2022-12-05 22:29:52 +08:00
|
|
|
return
|
|
|
|
}
|
2021-12-02 22:56:17 +08:00
|
|
|
|
2022-12-05 22:29:52 +08:00
|
|
|
func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy) (subRules map[string][]C.Rule, err error) {
|
2022-12-06 09:04:30 +08:00
|
|
|
subRules = map[string][]C.Rule{}
|
2023-07-16 10:14:29 +08:00
|
|
|
for name := range cfg.SubRules {
|
|
|
|
subRules[name] = make([]C.Rule, 0)
|
|
|
|
}
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
for name, rawRules := range cfg.SubRules {
|
2022-12-04 13:37:14 +08:00
|
|
|
if len(name) == 0 {
|
2022-12-05 22:29:52 +08:00
|
|
|
return nil, fmt.Errorf("sub-rule name is empty")
|
2022-12-04 13:37:14 +08:00
|
|
|
}
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
var rules []C.Rule
|
2022-12-05 22:29:52 +08:00
|
|
|
rules, err = parseRules(rawRules, proxies, subRules, fmt.Sprintf("sub-rules[%s]", name))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
}
|
2022-12-04 13:37:14 +08:00
|
|
|
subRules[name] = rules
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if err = verifySubRule(subRules); err != nil {
|
2022-12-05 22:29:52 +08:00
|
|
|
return nil, err
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-12-04 13:37:14 +08:00
|
|
|
func verifySubRule(subRules map[string][]C.Rule) error {
|
|
|
|
for name := range subRules {
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
err := verifySubRuleCircularReferences(name, subRules, []string{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-12-04 13:37:14 +08:00
|
|
|
func verifySubRuleCircularReferences(n string, subRules map[string][]C.Rule, arr []string) error {
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
isInArray := func(v string, array []string) bool {
|
|
|
|
for _, c := range array {
|
|
|
|
if v == c {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
arr = append(arr, n)
|
2022-12-04 13:37:14 +08:00
|
|
|
for i, rule := range subRules[n] {
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
if rule.RuleType() == C.SubRules {
|
2022-12-04 13:37:14 +08:00
|
|
|
if _, ok := subRules[rule.Adapter()]; !ok {
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
return fmt.Errorf("sub-rule[%d:%s] error: [%s] not found", i, n, rule.Adapter())
|
|
|
|
}
|
|
|
|
if isInArray(rule.Adapter(), arr) {
|
|
|
|
arr = append(arr, rule.Adapter())
|
|
|
|
return fmt.Errorf("sub-rule error: circular references [%s]", strings.Join(arr, "->"))
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := verifySubRuleCircularReferences(rule.Adapter(), subRules, arr); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-12-05 22:29:52 +08:00
|
|
|
func parseRules(rulesConfig []string, proxies map[string]C.Proxy, subRules map[string][]C.Rule, format string) ([]C.Rule, error) {
|
2022-01-05 00:33:42 +08:00
|
|
|
var rules []C.Rule
|
2021-11-17 16:03:47 +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-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
|
|
|
)
|
|
|
|
|
2022-03-17 17:41:02 +08:00
|
|
|
l := len(rule)
|
2022-03-15 02:55:06 +08:00
|
|
|
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" || ruleName == "SUB-RULE" {
|
2022-03-17 17:41:02 +08:00
|
|
|
target = rule[l-1]
|
|
|
|
payload = strings.Join(rule[1:l-1], ",")
|
2022-01-22 22:10:45 +08:00
|
|
|
} else {
|
2022-03-17 17:41:02 +08:00
|
|
|
if l < 2 {
|
2022-12-05 22:29:52 +08:00
|
|
|
return nil, fmt.Errorf("%s[%d] [%s] error: format invalid", format, idx, line)
|
2022-03-17 17:41:02 +08:00
|
|
|
}
|
|
|
|
if l < 4 {
|
|
|
|
rule = append(rule, make([]string, 4-l)...)
|
|
|
|
}
|
|
|
|
if ruleName == "MATCH" {
|
|
|
|
l = 2
|
|
|
|
}
|
|
|
|
if l >= 3 {
|
|
|
|
l = 3
|
2022-01-22 22:10:45 +08:00
|
|
|
payload = rule[1]
|
2022-03-17 17:41:02 +08:00
|
|
|
}
|
|
|
|
target = rule[l-1]
|
|
|
|
params = rule[l:]
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
2022-04-11 06:28:42 +08:00
|
|
|
if _, ok := proxies[target]; !ok {
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
if ruleName != "SUB-RULE" {
|
2022-12-05 22:29:52 +08:00
|
|
|
return nil, fmt.Errorf("%s[%d] [%s] error: proxy [%s] not found", format, idx, line, target)
|
2022-12-04 13:37:14 +08:00
|
|
|
} else if _, ok = subRules[target]; !ok {
|
2022-12-05 22:29:52 +08:00
|
|
|
return nil, fmt.Errorf("%s[%d] [%s] error: sub-rule [%s] not found", format, idx, line, target)
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
}
|
2019-06-20 11:03:50 +08:00
|
|
|
}
|
|
|
|
|
2019-10-28 00:02:23 +08:00
|
|
|
params = trimArr(params)
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
parsed, parseErr := R.ParseRule(ruleName, payload, target, params, subRules)
|
2019-10-28 00:02:23 +08:00
|
|
|
if parseErr != nil {
|
2022-12-05 22:29:52 +08:00
|
|
|
return nil, fmt.Errorf("%s[%d] [%s] error: %s", format, idx, line, parseErr.Error())
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
|
|
|
|
2022-04-11 06:28:42 +08:00
|
|
|
rules = append(rules, parsed)
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
2022-02-06 01:59:35 +08:00
|
|
|
|
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
|
|
|
return rules, nil
|
2018-07-26 00:04:59 +08:00
|
|
|
}
|
2018-12-05 21:13:29 +08:00
|
|
|
|
2023-03-12 15:00:59 +08:00
|
|
|
func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) {
|
|
|
|
tree := trie.New[resolver.HostValue]()
|
2020-06-07 17:25:51 +08:00
|
|
|
|
|
|
|
// add default hosts
|
2023-03-12 15:00:59 +08:00
|
|
|
hostValue, _ := resolver.NewHostValueByIPs(
|
|
|
|
[]netip.Addr{netip.AddrFrom4([4]byte{127, 0, 0, 1})})
|
|
|
|
if err := tree.Insert("localhost", hostValue); 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 {
|
2023-03-12 15:00:59 +08:00
|
|
|
for domain, anyValue := range cfg.Hosts {
|
2023-11-30 21:12:30 +08:00
|
|
|
if str, ok := anyValue.(string); ok && str == "lan" {
|
2023-03-12 15:00:59 +08:00
|
|
|
if addrs, err := net.InterfaceAddrs(); err != nil {
|
2023-11-30 21:12:30 +08:00
|
|
|
log.Errorln("insert lan to host error: %s", err)
|
2023-03-12 15:00:59 +08:00
|
|
|
} else {
|
|
|
|
ips := make([]netip.Addr, 0)
|
|
|
|
for _, addr := range addrs {
|
2023-04-26 15:57:55 +08:00
|
|
|
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && !ipnet.IP.IsLinkLocalUnicast() {
|
2023-03-12 15:00:59 +08:00
|
|
|
if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil {
|
|
|
|
ips = append(ips, ip)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
anyValue = ips
|
|
|
|
}
|
|
|
|
}
|
|
|
|
value, err := resolver.NewHostValue(anyValue)
|
2022-04-11 06:28:42 +08:00
|
|
|
if err != nil {
|
2023-03-12 15:00:59 +08:00
|
|
|
return nil, fmt.Errorf("%s is not a valid value", anyValue)
|
|
|
|
}
|
|
|
|
if value.IsDomain {
|
|
|
|
node := tree.Search(value.Domain)
|
|
|
|
for node != nil && node.Data().IsDomain {
|
|
|
|
if node.Data().Domain == domain {
|
|
|
|
return nil, fmt.Errorf("%s, there is a cycle in domain name mapping", domain)
|
|
|
|
}
|
|
|
|
node = tree.Search(node.Data().Domain)
|
|
|
|
}
|
2019-09-11 17:00:55 +08:00
|
|
|
}
|
2023-03-12 15:00:59 +08:00
|
|
|
_ = tree.Insert(domain, value)
|
2019-09-11 17:00:55 +08:00
|
|
|
}
|
|
|
|
}
|
2022-11-30 19:42:05 +08:00
|
|
|
tree.Optimize()
|
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
|
|
|
hostname, port, err := net.SplitHostPort(host)
|
2023-01-28 16:09:14 +08:00
|
|
|
if err != nil {
|
|
|
|
if !strings.Contains(err.Error(), "missing port in address") {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
host = host + ":" + defPort
|
|
|
|
if hostname, port, err = net.SplitHostPort(host); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
2020-02-17 22:13:15 +08:00
|
|
|
return net.JoinHostPort(hostname, port), nil
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
2022-11-12 11:14:51 +08:00
|
|
|
func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) {
|
2022-03-15 02:55:06 +08:00
|
|
|
var nameservers []dns.NameServer
|
2018-12-05 21:13:29 +08:00
|
|
|
|
|
|
|
for idx, server := range servers {
|
2023-01-27 17:10:15 +08:00
|
|
|
server = parsePureDNSServer(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())
|
|
|
|
}
|
|
|
|
|
2023-04-11 10:29:55 +08:00
|
|
|
proxyName := u.Fragment
|
2022-12-07 13:00:45 +08:00
|
|
|
|
|
|
|
var addr, dnsNetType string
|
2022-07-21 14:03:49 +08:00
|
|
|
params := map[string]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":
|
2023-02-17 23:30:38 +08:00
|
|
|
addr, err = hostWithDefaultPort(u.Host, "443")
|
|
|
|
if err == nil {
|
2023-04-11 10:29:55 +08:00
|
|
|
proxyName = ""
|
2023-06-06 09:45:05 +08:00
|
|
|
clearURL := url.URL{Scheme: "https", Host: addr, Path: u.Path, User: u.User}
|
2023-02-17 23:30:38 +08:00
|
|
|
addr = clearURL.String()
|
|
|
|
dnsNetType = "https" // DNS over HTTPS
|
|
|
|
if len(u.Fragment) != 0 {
|
|
|
|
for _, s := range strings.Split(u.Fragment, "&") {
|
|
|
|
arr := strings.Split(s, "=")
|
|
|
|
if len(arr) == 0 {
|
|
|
|
continue
|
|
|
|
} else if len(arr) == 1 {
|
2023-04-11 10:29:55 +08:00
|
|
|
proxyName = arr[0]
|
2023-02-17 23:30:38 +08:00
|
|
|
} else if len(arr) == 2 {
|
|
|
|
params[arr[0]] = arr[1]
|
|
|
|
} else {
|
|
|
|
params[arr[0]] = strings.Join(arr[1:], "=")
|
|
|
|
}
|
2022-07-21 14:03:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
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":
|
2022-06-12 17:53:11 +08:00
|
|
|
addr, err = hostWithDefaultPort(u.Host, "853")
|
2022-01-27 12:25:53 +08:00
|
|
|
dnsNetType = "quic" // DNS over QUIC
|
2023-04-26 15:57:55 +08:00
|
|
|
case "system":
|
|
|
|
dnsNetType = "system" // System DNS
|
2023-06-11 23:01:45 +08:00
|
|
|
case "rcode":
|
|
|
|
dnsNetType = "rcode"
|
|
|
|
addr = u.Host
|
|
|
|
switch addr {
|
|
|
|
case "success",
|
|
|
|
"format_error",
|
|
|
|
"server_failure",
|
|
|
|
"name_error",
|
|
|
|
"not_implemented",
|
|
|
|
"refused":
|
|
|
|
default:
|
|
|
|
err = fmt.Errorf("unsupported RCode type: %s", addr)
|
|
|
|
}
|
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{
|
2023-04-11 10:29:55 +08:00
|
|
|
Net: dnsNetType,
|
|
|
|
Addr: addr,
|
|
|
|
ProxyName: proxyName,
|
|
|
|
Params: params,
|
|
|
|
PreferH3: preferH3,
|
2018-12-05 21:13:29 +08:00
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return nameservers, nil
|
|
|
|
}
|
|
|
|
|
2023-04-11 10:29:55 +08:00
|
|
|
func init() {
|
|
|
|
dns.ParseNameServer = func(servers []string) ([]dns.NameServer, error) { // using by wireguard
|
|
|
|
return parseNameServer(servers, false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-27 17:02:58 +08:00
|
|
|
func parsePureDNSServer(server string) string {
|
2023-01-27 13:07:52 +08:00
|
|
|
addPre := func(server string) string {
|
|
|
|
return "udp://" + server
|
|
|
|
}
|
2023-01-27 15:08:05 +08:00
|
|
|
|
2023-05-01 12:58:02 +08:00
|
|
|
if server == "system" {
|
|
|
|
return "system://"
|
|
|
|
}
|
|
|
|
|
2023-01-28 16:09:14 +08:00
|
|
|
if ip, err := netip.ParseAddr(server); err != nil {
|
2023-01-27 15:08:05 +08:00
|
|
|
if strings.Contains(server, "://") {
|
2023-01-27 17:02:58 +08:00
|
|
|
return server
|
2023-01-27 13:07:52 +08:00
|
|
|
}
|
2023-01-28 16:09:14 +08:00
|
|
|
return addPre(server)
|
2023-01-27 13:07:52 +08:00
|
|
|
} else {
|
2023-01-28 16:09:14 +08:00
|
|
|
if ip.Is4() {
|
|
|
|
return addPre(server)
|
|
|
|
} else {
|
|
|
|
return addPre("[" + server + "]")
|
|
|
|
}
|
2023-01-27 13:07:52 +08:00
|
|
|
}
|
|
|
|
}
|
2023-11-09 08:47:44 +08:00
|
|
|
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]providerTypes.RuleProvider, preferH3 bool) (*orderedmap.OrderedMap[string, []dns.NameServer], error) {
|
|
|
|
policy := orderedmap.New[string, []dns.NameServer]()
|
|
|
|
updatedPolicy := orderedmap.New[string, any]()
|
2023-03-12 16:42:41 +08:00
|
|
|
re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`)
|
|
|
|
|
2023-11-09 08:47:44 +08:00
|
|
|
for pair := nsPolicy.Oldest(); pair != nil; pair = pair.Next() {
|
|
|
|
k, v := pair.Key, pair.Value
|
2023-12-05 20:29:56 +08:00
|
|
|
if strings.Contains(strings.ToLower(k), ",") {
|
2023-03-14 14:23:10 +08:00
|
|
|
if strings.Contains(k, "geosite:") {
|
|
|
|
subkeys := strings.Split(k, ":")
|
|
|
|
subkeys = subkeys[1:]
|
|
|
|
subkeys = strings.Split(subkeys[0], ",")
|
|
|
|
for _, subkey := range subkeys {
|
|
|
|
newKey := "geosite:" + subkey
|
2023-11-09 08:47:44 +08:00
|
|
|
updatedPolicy.Store(newKey, v)
|
2023-03-14 14:23:10 +08:00
|
|
|
}
|
2023-12-05 20:29:56 +08:00
|
|
|
} else if strings.Contains(strings.ToLower(k), "rule-set:") {
|
2023-04-01 11:53:39 +08:00
|
|
|
subkeys := strings.Split(k, ":")
|
|
|
|
subkeys = subkeys[1:]
|
|
|
|
subkeys = strings.Split(subkeys[0], ",")
|
|
|
|
for _, subkey := range subkeys {
|
|
|
|
newKey := "rule-set:" + subkey
|
2023-11-09 08:47:44 +08:00
|
|
|
updatedPolicy.Store(newKey, v)
|
2023-04-01 11:53:39 +08:00
|
|
|
}
|
2023-03-14 14:23:10 +08:00
|
|
|
} else if re.MatchString(k) {
|
|
|
|
subkeys := strings.Split(k, ",")
|
|
|
|
for _, subkey := range subkeys {
|
2023-11-09 08:47:44 +08:00
|
|
|
updatedPolicy.Store(subkey, v)
|
2023-03-14 14:23:10 +08:00
|
|
|
}
|
2023-03-12 16:42:41 +08:00
|
|
|
}
|
|
|
|
} else {
|
2023-12-05 20:29:56 +08:00
|
|
|
if strings.Contains(strings.ToLower(k), "geosite:") {
|
|
|
|
updatedPolicy.Store("geosite:"+k[8:], v)
|
|
|
|
} else if strings.Contains(strings.ToLower(k), "rule-set:") {
|
|
|
|
updatedPolicy.Store("rule-set:"+k[9:], v)
|
|
|
|
}
|
2023-11-09 08:47:44 +08:00
|
|
|
updatedPolicy.Store(k, v)
|
2023-03-12 16:42:41 +08:00
|
|
|
}
|
|
|
|
}
|
2021-05-19 11:17:35 +08:00
|
|
|
|
2023-11-09 08:47:44 +08:00
|
|
|
for pair := updatedPolicy.Oldest(); pair != nil; pair = pair.Next() {
|
|
|
|
domain, server := pair.Key, pair.Value
|
2023-03-12 15:00:59 +08:00
|
|
|
servers, err := utils.ToStringSlice(server)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2023-02-03 21:40:05 +08:00
|
|
|
}
|
2023-03-12 15:00:59 +08:00
|
|
|
nameservers, err := parseNameServer(servers, preferH3)
|
2021-05-19 11:17:35 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if _, valid := trie.ValidAndSplitDomain(domain); !valid {
|
|
|
|
return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain)
|
|
|
|
}
|
2023-04-01 11:53:39 +08:00
|
|
|
if strings.HasPrefix(domain, "rule-set:") {
|
|
|
|
domainSetName := domain[9:]
|
|
|
|
if provider, ok := ruleProviders[domainSetName]; !ok {
|
|
|
|
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
|
|
|
|
} else {
|
|
|
|
switch provider.Behavior() {
|
|
|
|
case providerTypes.IPCIDR:
|
|
|
|
return nil, fmt.Errorf("rule provider type error, except domain,actual %s", provider.Behavior())
|
|
|
|
case providerTypes.Classical:
|
|
|
|
log.Warnln("%s provider is %s, only matching it contain domain rule", provider.Name(), provider.Behavior())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-11-09 08:47:44 +08:00
|
|
|
policy.Store(domain, nameservers)
|
2021-05-19 11:17:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return policy, nil
|
|
|
|
}
|
|
|
|
|
2023-10-26 10:39:54 +08:00
|
|
|
func parseFallbackIPCIDR(ips []string) ([]netip.Prefix, error) {
|
|
|
|
var ipNets []netip.Prefix
|
2019-09-15 13:36:45 +08:00
|
|
|
|
|
|
|
for idx, ip := range ips {
|
2022-04-20 01:52:51 +08:00
|
|
|
ipnet, err := netip.ParsePrefix(ip)
|
2019-09-15 13:36:45 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %s", idx, err.Error())
|
|
|
|
}
|
2023-10-26 10:39:54 +08:00
|
|
|
ipNets = append(ipNets, ipnet)
|
2019-09-15 13:36:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2022-06-10 13:36:09 +08:00
|
|
|
if err := geodata.InitGeoSite(); err != nil {
|
2022-03-18 01:25:59 +08:00
|
|
|
return nil, fmt.Errorf("can't initial GeoSite: %s", err)
|
2022-01-11 22:17:24 +08:00
|
|
|
}
|
2023-02-17 13:48:29 +08:00
|
|
|
log.Warnln("replace fallback-filter.geosite with nameserver-policy, it will be removed in the future")
|
2022-01-11 22:17:24 +08:00
|
|
|
}
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sites, nil
|
|
|
|
}
|
|
|
|
|
2023-09-01 03:11:35 +08:00
|
|
|
func paresNTP(rawCfg *RawConfig) *NTP {
|
|
|
|
cfg := rawCfg.NTP
|
|
|
|
ntpCfg := &NTP{
|
2023-09-03 17:48:52 +08:00
|
|
|
Enable: cfg.Enable,
|
|
|
|
Server: cfg.Server,
|
|
|
|
Port: cfg.ServerPort,
|
|
|
|
Interval: cfg.Interval,
|
2023-09-25 09:11:20 +08:00
|
|
|
DialerProxy: cfg.DialerProxy,
|
2023-09-03 17:48:52 +08:00
|
|
|
WriteToSystem: cfg.WriteToSystem,
|
2023-09-01 03:11:35 +08:00
|
|
|
}
|
|
|
|
return ntpCfg
|
|
|
|
}
|
|
|
|
|
2023-04-01 11:53:39 +08:00
|
|
|
func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (*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,
|
2022-07-06 20:53:34 +08:00
|
|
|
PreferH3: cfg.PreferH3,
|
2023-03-10 23:38:16 +08:00
|
|
|
IPv6Timeout: cfg.IPv6Timeout,
|
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{
|
2023-10-26 10:39:54 +08:00
|
|
|
IPCIDR: []netip.Prefix{},
|
2021-11-17 16:03:47 +08:00
|
|
|
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
|
2022-11-12 11:14:51 +08:00
|
|
|
if dnsCfg.NameServer, err = parseNameServer(cfg.NameServer, cfg.PreferH3); err != nil {
|
2019-03-01 00:52:30 +08:00
|
|
|
return nil, err
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
2022-11-12 11:14:51 +08:00
|
|
|
if dnsCfg.Fallback, err = parseNameServer(cfg.Fallback, cfg.PreferH3); err != nil {
|
2019-03-01 00:52:30 +08:00
|
|
|
return nil, err
|
2018-12-05 21:13:29 +08:00
|
|
|
}
|
|
|
|
|
2023-04-01 11:53:39 +08:00
|
|
|
if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, ruleProviders, cfg.PreferH3); err != nil {
|
2021-05-19 11:17:35 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-11-12 11:14:51 +08:00
|
|
|
if dnsCfg.ProxyServerNameserver, err = parseNameServer(cfg.ProxyServerNameserver, cfg.PreferH3); err != nil {
|
2022-03-28 00:44:13 +08:00
|
|
|
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")
|
|
|
|
}
|
2022-11-12 11:14:51 +08:00
|
|
|
if dnsCfg.DefaultNameserver, err = parseNameServer(cfg.DefaultNameserver, cfg.PreferH3); err != nil {
|
2020-02-15 21:42:46 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// check default nameserver is pure ip addr
|
|
|
|
for _, ns := range dnsCfg.DefaultNameserver {
|
2023-05-01 12:41:36 +08:00
|
|
|
if ns.Net == "system" {
|
|
|
|
continue
|
|
|
|
}
|
2020-02-17 22:13:15 +08:00
|
|
|
host, _, err := net.SplitHostPort(ns.Addr)
|
|
|
|
if err != nil || net.ParseIP(host) == nil {
|
2022-04-03 19:14:21 +08:00
|
|
|
u, err := url.Parse(ns.Addr)
|
2022-07-12 13:05:59 +08:00
|
|
|
if err == nil && net.ParseIP(u.Host) == nil {
|
2022-07-11 22:05:37 +08:00
|
|
|
if ip, _, err := net.SplitHostPort(u.Host); err != nil || net.ParseIP(ip) == nil {
|
|
|
|
return nil, errors.New("default nameserver should be pure IP")
|
|
|
|
}
|
2022-04-03 19:14:21 +08:00
|
|
|
}
|
2020-02-15 21:42:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-10 21:08:06 +08:00
|
|
|
fakeIPRange, err := netip.ParsePrefix(cfg.FakeIPRange)
|
|
|
|
T.SetFakeIPRange(fakeIPRange)
|
2021-10-18 21:08:27 +08:00
|
|
|
if cfg.EnhancedMode == C.DNSFakeIP {
|
2019-05-03 00:05:14 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-12-28 00:10:06 +08:00
|
|
|
|
2022-11-02 22:28:18 +08:00
|
|
|
var host *trie.DomainTrie[struct{}]
|
2019-12-28 00:10:06 +08:00
|
|
|
// fake ip skip host filter
|
|
|
|
if len(cfg.FakeIPFilter) != 0 {
|
2022-11-02 22:28:18 +08:00
|
|
|
host = trie.New[struct{}]()
|
2019-12-28 00:10:06 +08:00
|
|
|
for _, domain := range cfg.FakeIPFilter {
|
2022-11-02 22:28:18 +08:00
|
|
|
_ = host.Insert(domain, struct{}{})
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
2022-11-30 19:42:05 +08:00
|
|
|
host.Optimize()
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(dnsCfg.Fallback) != 0 {
|
|
|
|
if host == nil {
|
2022-11-02 22:28:18 +08:00
|
|
|
host = trie.New[struct{}]()
|
2021-11-17 16:03:47 +08:00
|
|
|
}
|
|
|
|
for _, fb := range dnsCfg.Fallback {
|
|
|
|
if net.ParseIP(fb.Addr) != nil {
|
|
|
|
continue
|
|
|
|
}
|
2022-11-02 22:28:18 +08:00
|
|
|
_ = host.Insert(fb.Addr, struct{}{})
|
2019-12-28 00:10:06 +08:00
|
|
|
}
|
2022-11-30 19:42:05 +08:00
|
|
|
host.Optimize()
|
2019-12-28 00:10:06 +08:00
|
|
|
}
|
|
|
|
|
2021-10-11 20:48:58 +08:00
|
|
|
pool, err := fakeip.New(fakeip.Options{
|
2023-10-26 10:39:54 +08:00
|
|
|
IPNet: fakeIPRange,
|
2021-10-11 20:48:58 +08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-12-02 17:07:36 +08:00
|
|
|
if cfg.CacheAlgorithm == "" || cfg.CacheAlgorithm == "lru" {
|
|
|
|
dnsCfg.CacheAlgorithm = "lru"
|
|
|
|
} else {
|
|
|
|
dnsCfg.CacheAlgorithm = "arc"
|
|
|
|
}
|
|
|
|
|
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 {
|
2022-03-28 16:36:34 +08:00
|
|
|
var users []auth.AuthUser
|
2019-06-27 17:04:25 +08:00
|
|
|
for _, line := range rawRecords {
|
2022-03-16 12:10:13 +08:00
|
|
|
if user, pass, found := strings.Cut(line, ":"); found {
|
|
|
|
users = append(users, auth.AuthUser{User: user, Pass: pass})
|
2019-06-27 17:04:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return users
|
|
|
|
}
|
2021-11-17 16:03:47 +08:00
|
|
|
|
2022-11-10 21:08:06 +08:00
|
|
|
func parseTun(rawTun RawTun, general *General) error {
|
|
|
|
tunAddressPrefix := T.FakeIPRange()
|
|
|
|
if !tunAddressPrefix.IsValid() {
|
2022-05-28 23:29:03 +08:00
|
|
|
tunAddressPrefix = netip.MustParsePrefix("198.18.0.1/16")
|
2022-05-19 19:19:19 +08:00
|
|
|
}
|
2022-10-09 10:48:26 +08:00
|
|
|
tunAddressPrefix = netip.PrefixFrom(tunAddressPrefix.Addr(), 30)
|
2022-05-19 19:19:19 +08:00
|
|
|
|
2022-12-03 00:10:50 +08:00
|
|
|
if !general.IPv6 || !verifyIP6() {
|
|
|
|
rawTun.Inet6Address = nil
|
|
|
|
}
|
|
|
|
|
2022-12-06 09:04:30 +08:00
|
|
|
general.Tun = LC.Tun{
|
2022-04-23 23:42:42 +08:00
|
|
|
Enable: rawTun.Enable,
|
|
|
|
Device: rawTun.Device,
|
|
|
|
Stack: rawTun.Stack,
|
2022-12-06 09:04:30 +08:00
|
|
|
DNSHijack: rawTun.DNSHijack,
|
2022-04-23 23:42:42 +08:00
|
|
|
AutoRoute: rawTun.AutoRoute,
|
|
|
|
AutoDetectInterface: rawTun.AutoDetectInterface,
|
2022-08-22 23:17:41 +08:00
|
|
|
RedirectToTun: rawTun.RedirectToTun,
|
2022-10-06 22:18:49 +08:00
|
|
|
|
2023-11-02 11:37:40 +08:00
|
|
|
MTU: rawTun.MTU,
|
|
|
|
Inet4Address: []netip.Prefix{tunAddressPrefix},
|
|
|
|
Inet6Address: rawTun.Inet6Address,
|
|
|
|
StrictRoute: rawTun.StrictRoute,
|
|
|
|
Inet4RouteAddress: rawTun.Inet4RouteAddress,
|
|
|
|
Inet6RouteAddress: rawTun.Inet6RouteAddress,
|
|
|
|
Inet4RouteExcludeAddress: rawTun.Inet4RouteExcludeAddress,
|
|
|
|
Inet6RouteExcludeAddress: rawTun.Inet6RouteExcludeAddress,
|
|
|
|
IncludeUID: rawTun.IncludeUID,
|
|
|
|
IncludeUIDRange: rawTun.IncludeUIDRange,
|
|
|
|
ExcludeUID: rawTun.ExcludeUID,
|
|
|
|
ExcludeUIDRange: rawTun.ExcludeUIDRange,
|
|
|
|
IncludeAndroidUser: rawTun.IncludeAndroidUser,
|
|
|
|
IncludePackage: rawTun.IncludePackage,
|
|
|
|
ExcludePackage: rawTun.ExcludePackage,
|
|
|
|
EndpointIndependentNat: rawTun.EndpointIndependentNat,
|
|
|
|
UDPTimeout: rawTun.UDPTimeout,
|
|
|
|
FileDescriptor: rawTun.FileDescriptor,
|
2022-11-04 08:52:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2022-03-09 05:08:35 +08:00
|
|
|
}
|
2022-04-09 22:30:36 +08:00
|
|
|
|
2022-11-28 17:09:25 +08:00
|
|
|
func parseTuicServer(rawTuic RawTuicServer, general *General) error {
|
2022-12-06 09:04:30 +08:00
|
|
|
general.TuicServer = LC.TuicServer{
|
2022-11-28 17:09:25 +08:00
|
|
|
Enable: rawTuic.Enable,
|
|
|
|
Listen: rawTuic.Listen,
|
|
|
|
Token: rawTuic.Token,
|
2023-06-12 17:44:22 +08:00
|
|
|
Users: rawTuic.Users,
|
2022-11-28 17:09:25 +08:00
|
|
|
Certificate: rawTuic.Certificate,
|
|
|
|
PrivateKey: rawTuic.PrivateKey,
|
|
|
|
CongestionController: rawTuic.CongestionController,
|
|
|
|
MaxIdleTime: rawTuic.MaxIdleTime,
|
|
|
|
AuthenticationTimeout: rawTuic.AuthenticationTimeout,
|
|
|
|
ALPN: rawTuic.ALPN,
|
|
|
|
MaxUdpRelayPacketSize: rawTuic.MaxUdpRelayPacketSize,
|
2023-06-21 14:00:49 +08:00
|
|
|
CWND: rawTuic.CWND,
|
2022-11-28 17:09:25 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-05-16 17:29:08 +08:00
|
|
|
func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) {
|
2022-04-09 22:30:36 +08:00
|
|
|
sniffer := &Sniffer{
|
2022-10-14 07:46:33 +08:00
|
|
|
Enable: snifferRaw.Enable,
|
|
|
|
ForceDnsMapping: snifferRaw.ForceDnsMapping,
|
2022-10-14 08:42:28 +08:00
|
|
|
ParsePureIp: snifferRaw.ParsePureIp,
|
2022-04-09 22:30:36 +08:00
|
|
|
}
|
2023-01-23 13:16:25 +08:00
|
|
|
loadSniffer := make(map[snifferTypes.Type]SNIFF.SnifferConfig)
|
2022-04-09 22:30:36 +08:00
|
|
|
|
2023-01-23 13:16:25 +08:00
|
|
|
if len(snifferRaw.Sniff) != 0 {
|
|
|
|
for sniffType, sniffConfig := range snifferRaw.Sniff {
|
|
|
|
find := false
|
2023-06-04 11:51:30 +08:00
|
|
|
ports, err := utils.NewIntRangesFromList[uint16](sniffConfig.Ports)
|
2022-04-23 09:36:11 +08:00
|
|
|
if err != nil {
|
2023-01-23 13:16:25 +08:00
|
|
|
return nil, err
|
2022-04-23 09:36:11 +08:00
|
|
|
}
|
2023-01-23 14:08:11 +08:00
|
|
|
overrideDest := snifferRaw.OverrideDest
|
|
|
|
if sniffConfig.OverrideDest != nil {
|
|
|
|
overrideDest = *sniffConfig.OverrideDest
|
|
|
|
}
|
2023-01-23 13:16:25 +08:00
|
|
|
for _, snifferType := range snifferTypes.List {
|
|
|
|
if snifferType.String() == strings.ToUpper(sniffType) {
|
|
|
|
find = true
|
|
|
|
loadSniffer[snifferType] = SNIFF.SnifferConfig{
|
2023-01-23 14:08:11 +08:00
|
|
|
Ports: ports,
|
|
|
|
OverrideDest: overrideDest,
|
2023-01-23 13:16:25 +08:00
|
|
|
}
|
2022-04-21 22:06:08 +08:00
|
|
|
}
|
2023-01-23 13:16:25 +08:00
|
|
|
}
|
2022-04-21 22:06:08 +08:00
|
|
|
|
2023-01-23 13:16:25 +08:00
|
|
|
if !find {
|
|
|
|
return nil, fmt.Errorf("not find the sniffer[%s]", sniffType)
|
2022-04-21 22:06:08 +08:00
|
|
|
}
|
|
|
|
}
|
2023-01-23 13:16:25 +08:00
|
|
|
} else {
|
2023-03-10 20:48:18 +08:00
|
|
|
if sniffer.Enable {
|
|
|
|
// Deprecated: Use Sniff instead
|
|
|
|
log.Warnln("Deprecated: Use Sniff instead")
|
|
|
|
}
|
2023-06-04 11:51:30 +08:00
|
|
|
globalPorts, err := utils.NewIntRangesFromList[uint16](snifferRaw.Ports)
|
2023-01-23 13:16:25 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-04-09 22:30:36 +08:00
|
|
|
|
2023-01-23 13:16:25 +08:00
|
|
|
for _, snifferName := range snifferRaw.Sniffing {
|
|
|
|
find := false
|
|
|
|
for _, snifferType := range snifferTypes.List {
|
|
|
|
if snifferType.String() == strings.ToUpper(snifferName) {
|
|
|
|
find = true
|
|
|
|
loadSniffer[snifferType] = SNIFF.SnifferConfig{
|
2023-01-23 14:08:11 +08:00
|
|
|
Ports: globalPorts,
|
|
|
|
OverrideDest: snifferRaw.OverrideDest,
|
2023-01-23 13:16:25 +08:00
|
|
|
}
|
|
|
|
}
|
2022-04-09 22:30:36 +08:00
|
|
|
}
|
|
|
|
|
2023-01-23 13:16:25 +08:00
|
|
|
if !find {
|
|
|
|
return nil, fmt.Errorf("not find the sniffer[%s]", snifferName)
|
|
|
|
}
|
2022-04-09 22:30:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-23 13:16:25 +08:00
|
|
|
sniffer.Sniffers = loadSniffer
|
2023-04-01 12:15:03 +08:00
|
|
|
|
|
|
|
forceDomainTrie := trie.New[struct{}]()
|
|
|
|
for _, domain := range snifferRaw.ForceDomain {
|
|
|
|
err := forceDomainTrie.Insert(domain, struct{}{})
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sniffer.ForceDomain = forceDomainTrie.NewDomainSet()
|
|
|
|
|
|
|
|
skipDomainTrie := trie.New[struct{}]()
|
|
|
|
for _, domain := range snifferRaw.SkipDomain {
|
|
|
|
err := skipDomainTrie.Insert(domain, struct{}{})
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sniffer.SkipDomain = skipDomainTrie.NewDomainSet()
|
|
|
|
|
2022-04-09 22:30:36 +08:00
|
|
|
return sniffer, nil
|
|
|
|
}
|