feat: add linsters
This commit is contained in:
203
config/config.go
203
config/config.go
@ -15,9 +15,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/common/utils"
|
||||
"github.com/Dreamacro/clash/listener/sing_tun"
|
||||
"github.com/Dreamacro/clash/listener/tunnel"
|
||||
R "github.com/Dreamacro/clash/rules"
|
||||
RP "github.com/Dreamacro/clash/rules/provider"
|
||||
|
||||
L "github.com/Dreamacro/clash/listener"
|
||||
"github.com/Dreamacro/clash/adapter"
|
||||
"github.com/Dreamacro/clash/adapter/outbound"
|
||||
"github.com/Dreamacro/clash/adapter/outboundgroup"
|
||||
@ -30,13 +32,11 @@ import (
|
||||
"github.com/Dreamacro/clash/component/trie"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
providerTypes "github.com/Dreamacro/clash/constant/provider"
|
||||
"github.com/Dreamacro/clash/constant/sniffer"
|
||||
snifferTypes "github.com/Dreamacro/clash/constant/sniffer"
|
||||
"github.com/Dreamacro/clash/dns"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
T "github.com/Dreamacro/clash/tunnel"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@ -149,11 +149,11 @@ type Tun struct {
|
||||
RedirectToTun []string `yaml:"-" json:"-"`
|
||||
|
||||
MTU uint32 `yaml:"mtu" json:"mtu,omitempty"`
|
||||
Inet4Address []ListenPrefix `yaml:"inet4-address" json:"inet4-address,omitempty"`
|
||||
Inet6Address []ListenPrefix `yaml:"inet6-address" json:"inet6-address,omitempty"`
|
||||
Inet4Address []sing_tun.ListenPrefix `yaml:"inet4-address" json:"inet4-address,omitempty"`
|
||||
Inet6Address []sing_tun.ListenPrefix `yaml:"inet6-address" json:"inet6-address,omitempty"`
|
||||
StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"`
|
||||
Inet4RouteAddress []ListenPrefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"`
|
||||
Inet6RouteAddress []ListenPrefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"`
|
||||
Inet4RouteAddress []sing_tun.ListenPrefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"`
|
||||
Inet6RouteAddress []sing_tun.ListenPrefix `yaml:"inet6-route-address" json:"inet6-route-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"`
|
||||
@ -165,56 +165,6 @@ type Tun struct {
|
||||
UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"`
|
||||
}
|
||||
|
||||
type ListenPrefix netip.Prefix
|
||||
|
||||
func (p ListenPrefix) MarshalJSON() ([]byte, error) {
|
||||
prefix := netip.Prefix(p)
|
||||
if !prefix.IsValid() {
|
||||
return json.Marshal(nil)
|
||||
}
|
||||
return json.Marshal(prefix.String())
|
||||
}
|
||||
|
||||
func (p ListenPrefix) MarshalYAML() (interface{}, error) {
|
||||
prefix := netip.Prefix(p)
|
||||
if !prefix.IsValid() {
|
||||
return nil, nil
|
||||
}
|
||||
return prefix.String(), nil
|
||||
}
|
||||
|
||||
func (p *ListenPrefix) UnmarshalJSON(bytes []byte) error {
|
||||
var value string
|
||||
err := json.Unmarshal(bytes, &value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prefix, err := netip.ParsePrefix(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*p = ListenPrefix(prefix)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ListenPrefix) UnmarshalYAML(node *yaml.Node) error {
|
||||
var value string
|
||||
err := node.Decode(&value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prefix, err := netip.ParsePrefix(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*p = ListenPrefix(prefix)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p ListenPrefix) Build() netip.Prefix {
|
||||
return netip.Prefix(p)
|
||||
}
|
||||
|
||||
// IPTables config
|
||||
type IPTables struct {
|
||||
Enable bool `yaml:"enable" json:"enable"`
|
||||
@ -224,7 +174,7 @@ type IPTables struct {
|
||||
|
||||
type Sniffer struct {
|
||||
Enable bool
|
||||
Sniffers []sniffer.Type
|
||||
Sniffers []snifferTypes.Type
|
||||
Reverses *trie.DomainTrie[struct{}]
|
||||
ForceDomain *trie.DomainTrie[struct{}]
|
||||
SkipDomain *trie.DomainTrie[struct{}]
|
||||
@ -233,7 +183,6 @@ type Sniffer struct {
|
||||
ParsePureIp bool
|
||||
}
|
||||
|
||||
|
||||
// Experimental config
|
||||
type Experimental struct {
|
||||
Fingerprints []string `yaml:"fingerprints"`
|
||||
@ -248,12 +197,13 @@ type Config struct {
|
||||
Hosts *trie.DomainTrie[netip.Addr]
|
||||
Profile *Profile
|
||||
Rules []C.Rule
|
||||
SubRules *map[string][]C.Rule
|
||||
SubRules map[string][]C.Rule
|
||||
Users []auth.AuthUser
|
||||
Proxies map[string]C.Proxy
|
||||
Listeners map[string]C.NewListener
|
||||
Providers map[string]providerTypes.ProxyProvider
|
||||
RuleProviders map[string]providerTypes.RuleProvider
|
||||
Tunnels []Tunnel
|
||||
Tunnels []tunnel.Tunnel
|
||||
Sniffer *Sniffer
|
||||
TLS *TLS
|
||||
}
|
||||
@ -294,10 +244,10 @@ type RawTun struct {
|
||||
|
||||
MTU uint32 `yaml:"mtu" json:"mtu,omitempty"`
|
||||
//Inet4Address []ListenPrefix `yaml:"inet4-address" json:"inet4_address,omitempty"`
|
||||
Inet6Address []ListenPrefix `yaml:"inet6-address" json:"inet6_address,omitempty"`
|
||||
Inet6Address []sing_tun.ListenPrefix `yaml:"inet6-address" json:"inet6_address,omitempty"`
|
||||
StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"`
|
||||
Inet4RouteAddress []ListenPrefix `yaml:"inet4_route_address" json:"inet4_route_address,omitempty"`
|
||||
Inet6RouteAddress []ListenPrefix `yaml:"inet6_route_address" json:"inet6_route_address,omitempty"`
|
||||
Inet4RouteAddress []sing_tun.ListenPrefix `yaml:"inet4_route_address" json:"inet4_route_address,omitempty"`
|
||||
Inet6RouteAddress []sing_tun.ListenPrefix `yaml:"inet6_route_address" json:"inet6_route_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"`
|
||||
@ -322,65 +272,6 @@ type RawTuicServer struct {
|
||||
MaxUdpRelayPacketSize int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"`
|
||||
}
|
||||
|
||||
type tunnel struct {
|
||||
Network []string `yaml:"network"`
|
||||
Address string `yaml:"address"`
|
||||
Target string `yaml:"target"`
|
||||
Proxy string `yaml:"proxy"`
|
||||
}
|
||||
|
||||
type Tunnel tunnel
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler
|
||||
func (t *Tunnel) UnmarshalYAML(unmarshal func(any) error) error {
|
||||
var tp string
|
||||
if err := unmarshal(&tp); err != nil {
|
||||
var inner tunnel
|
||||
if err := unmarshal(&inner); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*t = Tunnel(inner)
|
||||
return nil
|
||||
}
|
||||
|
||||
// parse udp/tcp,address,target,proxy
|
||||
parts := lo.Map(strings.Split(tp, ","), func(s string, _ int) string {
|
||||
return strings.TrimSpace(s)
|
||||
})
|
||||
if len(parts) != 3 && len(parts) != 4 {
|
||||
return fmt.Errorf("invalid tunnel config %s", tp)
|
||||
}
|
||||
network := strings.Split(parts[0], "/")
|
||||
|
||||
// validate network
|
||||
for _, n := range network {
|
||||
switch n {
|
||||
case "tcp", "udp":
|
||||
default:
|
||||
return fmt.Errorf("invalid tunnel network %s", n)
|
||||
}
|
||||
}
|
||||
|
||||
// validate address and target
|
||||
address := parts[1]
|
||||
target := parts[2]
|
||||
for _, addr := range []string{address, target} {
|
||||
if _, _, err := net.SplitHostPort(addr); err != nil {
|
||||
return fmt.Errorf("invalid tunnel target or address %s", addr)
|
||||
}
|
||||
}
|
||||
|
||||
*t = Tunnel(tunnel{
|
||||
Network: network,
|
||||
Address: address,
|
||||
Target: target,
|
||||
})
|
||||
if len(parts) == 4 {
|
||||
t.Proxy = parts[3]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type RawConfig struct {
|
||||
Port int `yaml:"port"`
|
||||
@ -404,7 +295,7 @@ type RawConfig struct {
|
||||
Secret string `yaml:"secret"`
|
||||
Interface string `yaml:"interface-name"`
|
||||
RoutingMark int `yaml:"routing-mark"`
|
||||
Tunnels []Tunnel `yaml:"tunnels"`
|
||||
Tunnels []tunnel.Tunnel `yaml:"tunnels"`
|
||||
GeodataMode bool `yaml:"geodata-mode"`
|
||||
GeodataLoader string `yaml:"geodata-loader"`
|
||||
TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"`
|
||||
@ -426,7 +317,8 @@ type RawConfig struct {
|
||||
ProxyGroup []map[string]any `yaml:"proxy-groups"`
|
||||
Rule []string `yaml:"rules"`
|
||||
SubRules map[string][]string `yaml:"sub-rules"`
|
||||
RawTLS TLS `yaml:"tls"`
|
||||
RawTLS TLS `yaml:"tls"`
|
||||
Listeners []map[string]any `yaml:"listeners"`
|
||||
}
|
||||
|
||||
type RawGeoXUrl struct {
|
||||
@ -492,7 +384,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
|
||||
DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query
|
||||
AutoRoute: true,
|
||||
AutoDetectInterface: true,
|
||||
Inet6Address: []ListenPrefix{ListenPrefix(netip.MustParsePrefix("fdfe:dcba:9876::1/126"))},
|
||||
Inet6Address: []sing_tun.ListenPrefix{sing_tun.ListenPrefix(netip.MustParsePrefix("fdfe:dcba:9876::1/126"))},
|
||||
},
|
||||
TuicServer: RawTuicServer{
|
||||
Enable: false,
|
||||
@ -576,7 +468,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||
config.Experimental = &rawCfg.Experimental
|
||||
config.Profile = &rawCfg.Profile
|
||||
config.IPTables = &rawCfg.IPTables
|
||||
config.TLS=&rawCfg.RawTLS
|
||||
config.TLS = &rawCfg.RawTLS
|
||||
|
||||
general, err := parseGeneral(rawCfg)
|
||||
if err != nil {
|
||||
@ -585,7 +477,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||
config.General = general
|
||||
|
||||
dialer.DefaultInterface.Store(config.General.Interface)
|
||||
|
||||
proxies, providers, err := parseProxies(rawCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -593,6 +484,12 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||
config.Proxies = proxies
|
||||
config.Providers = providers
|
||||
|
||||
listener, err := parseListeners(rawCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Listeners = listener
|
||||
|
||||
subRules, ruleProviders, err := parseSubRules(rawCfg, proxies)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -645,7 +542,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms
|
||||
log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) //Segment finished in xxm
|
||||
|
||||
@ -677,9 +573,9 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
|
||||
InboundTfo: cfg.InboundTfo,
|
||||
},
|
||||
Controller: Controller{
|
||||
ExternalController: cfg.ExternalController,
|
||||
ExternalUI: cfg.ExternalUI,
|
||||
Secret: cfg.Secret,
|
||||
ExternalController: cfg.ExternalController,
|
||||
ExternalUI: cfg.ExternalUI,
|
||||
Secret: cfg.Secret,
|
||||
ExternalControllerTLS: cfg.ExternalControllerTLS,
|
||||
},
|
||||
UnifiedDelay: cfg.UnifiedDelay,
|
||||
@ -799,9 +695,27 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
|
||||
return proxies, providersMap, nil
|
||||
}
|
||||
|
||||
func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy) (subRules *map[string][]C.Rule, ruleProviders map[string]providerTypes.RuleProvider, err error) {
|
||||
func parseListeners(cfg *RawConfig) (listeners map[string]C.NewListener, err error) {
|
||||
listeners = make(map[string]C.NewListener)
|
||||
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
|
||||
}
|
||||
|
||||
func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy) (subRules map[string][]C.Rule, ruleProviders map[string]providerTypes.RuleProvider, err error) {
|
||||
ruleProviders = map[string]providerTypes.RuleProvider{}
|
||||
subRules = &map[string][]C.Rule{}
|
||||
subRules = map[string][]C.Rule{}
|
||||
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
|
||||
// parse rule provider
|
||||
for name, mapping := range cfg.RuleProvider {
|
||||
@ -815,6 +729,9 @@ func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy) (subRules *map[st
|
||||
}
|
||||
|
||||
for name, rawRules := range cfg.SubRules {
|
||||
if len(name) == 0 {
|
||||
return nil, nil, fmt.Errorf("sub-rule name is empty")
|
||||
}
|
||||
var rules []C.Rule
|
||||
for idx, line := range rawRules {
|
||||
rawRule := trimArr(strings.Split(line, ","))
|
||||
@ -860,7 +777,7 @@ func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy) (subRules *map[st
|
||||
|
||||
rules = append(rules, parsed)
|
||||
}
|
||||
(*subRules)[name] = rules
|
||||
subRules[name] = rules
|
||||
}
|
||||
|
||||
if err = verifySubRule(subRules); err != nil {
|
||||
@ -870,8 +787,8 @@ func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy) (subRules *map[st
|
||||
return
|
||||
}
|
||||
|
||||
func verifySubRule(subRules *map[string][]C.Rule) error {
|
||||
for name := range *subRules {
|
||||
func verifySubRule(subRules map[string][]C.Rule) error {
|
||||
for name := range subRules {
|
||||
err := verifySubRuleCircularReferences(name, subRules, []string{})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -880,7 +797,7 @@ func verifySubRule(subRules *map[string][]C.Rule) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifySubRuleCircularReferences(n string, subRules *map[string][]C.Rule, arr []string) error {
|
||||
func verifySubRuleCircularReferences(n string, subRules map[string][]C.Rule, arr []string) error {
|
||||
isInArray := func(v string, array []string) bool {
|
||||
for _, c := range array {
|
||||
if v == c {
|
||||
@ -891,9 +808,9 @@ func verifySubRuleCircularReferences(n string, subRules *map[string][]C.Rule, ar
|
||||
}
|
||||
|
||||
arr = append(arr, n)
|
||||
for i, rule := range (*subRules)[n] {
|
||||
for i, rule := range subRules[n] {
|
||||
if rule.RuleType() == C.SubRules {
|
||||
if _, ok := (*subRules)[rule.Adapter()]; !ok {
|
||||
if _, ok := subRules[rule.Adapter()]; !ok {
|
||||
return fmt.Errorf("sub-rule[%d:%s] error: [%s] not found", i, n, rule.Adapter())
|
||||
}
|
||||
if isInArray(rule.Adapter(), arr) {
|
||||
@ -909,7 +826,7 @@ func verifySubRuleCircularReferences(n string, subRules *map[string][]C.Rule, ar
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseRules(cfg *RawConfig, proxies map[string]C.Proxy, subRules *map[string][]C.Rule) ([]C.Rule, error) {
|
||||
func parseRules(cfg *RawConfig, proxies map[string]C.Proxy, subRules map[string][]C.Rule) ([]C.Rule, error) {
|
||||
var rules []C.Rule
|
||||
rulesConfig := cfg.Rule
|
||||
|
||||
@ -948,7 +865,7 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy, subRules *map[string
|
||||
if _, ok := proxies[target]; !ok {
|
||||
if ruleName != "SUB-RULE" {
|
||||
return nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target)
|
||||
} else if _, ok = (*subRules)[target]; !ok {
|
||||
} else if _, ok = subRules[target]; !ok {
|
||||
return nil, fmt.Errorf("rules[%d] [%s] error: sub-rule [%s] not found", idx, line, target)
|
||||
}
|
||||
}
|
||||
@ -1315,7 +1232,7 @@ func parseTun(rawTun RawTun, general *General) error {
|
||||
RedirectToTun: rawTun.RedirectToTun,
|
||||
|
||||
MTU: rawTun.MTU,
|
||||
Inet4Address: []ListenPrefix{ListenPrefix(tunAddressPrefix)},
|
||||
Inet4Address: []sing_tun.ListenPrefix{sing_tun.ListenPrefix(tunAddressPrefix)},
|
||||
Inet6Address: rawTun.Inet6Address,
|
||||
StrictRoute: rawTun.StrictRoute,
|
||||
Inet4RouteAddress: rawTun.Inet4RouteAddress,
|
||||
|
Reference in New Issue
Block a user