diff --git a/option/template.go b/option/template.go index 5ae2071..9590f37 100644 --- a/option/template.go +++ b/option/template.go @@ -21,6 +21,7 @@ type Template struct { DNSDefault string `json:"dns_default,omitempty"` DNSLocal string `json:"dns_local,omitempty"` EnableFakeIP bool `json:"enable_fakeip,omitempty"` + DisableDNSLeak bool `json:"disable_dns_leak,omitempty"` PreDNSRules []option.DNSRule `json:"pre_dns_rules,omitempty"` CustomDNSRules []option.DNSRule `json:"custom_dns_rules,omitempty"` @@ -51,14 +52,15 @@ type Template struct { CustomRuleSet []option.RuleSet `json:"custom_rule_set,omitempty"` // Experimental - DisableCacheFile bool `json:"disable_cache_file,omitempty"` - DisableExternalController bool `json:"disable_external_controller,omitempty"` - DisableClashMode bool `json:"disable_clash_mode,omitempty"` + DisableCacheFile bool `json:"disable_cache_file,omitempty"` + DisableExternalController bool `json:"disable_external_controller,omitempty"` + DisableClashMode bool `json:"disable_clash_mode,omitempty"` - ClashModeRule string `json:"clash_mode_rule,omitempty"` - ClashModeGlobal string `json:"clash_mode_global,omitempty"` - ClashModeDirect string `json:"clash_mode_direct,omitempty"` - CustomClashAPI *TypedMessage[option.ClashAPIOptions] `json:"custom_clash_api,omitempty"` + ClashModeLeak string `json:"clash_mode_leak,omitempty"` + ClashModeRule string `json:"clash_mode_rule,omitempty"` + ClashModeGlobal string `json:"clash_mode_global,omitempty"` + ClashModeDirect string `json:"clash_mode_direct,omitempty"` + CustomClashAPI *TypedMessage[option.ClashAPIOptions] `json:"custom_clash_api,omitempty"` // Debug PProfListen string `json:"pprof_listen,omitempty"` diff --git a/subscription/deduplication.go b/subscription/deduplication.go index 1d1aa67..9665308 100644 --- a/subscription/deduplication.go +++ b/subscription/deduplication.go @@ -9,7 +9,6 @@ import ( "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-dns" "github.com/sagernet/sing/common" - M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/task" ) @@ -21,8 +20,14 @@ func Deduplication(ctx context.Context, servers []option.Outbound) []option.Outb DisableExpire: true, Logger: log.NewNOPFactory().Logger(), }), - dnsTransport: common.Must1(dns.NewTLSTransport("google", ctx, N.SystemDialer, M.ParseSocksaddr("1.1.1.1"))), + dnsTransport: common.Must1(dns.NewTLSTransport(dns.TransportOptions{ + Context: ctx, + Dialer: N.SystemDialer, + Address: "tls://1.1.1.1", + ClientSubnet: netip.MustParseAddr("114.114.114.114"), + })), } + uniqueServers := make([]netip.AddrPort, len(servers)) var ( resolveGroup task.Group diff --git a/template/filter/filter_190.go b/template/filter/filter_190.go new file mode 100644 index 0000000..d0f5e68 --- /dev/null +++ b/template/filter/filter_190.go @@ -0,0 +1,30 @@ +package filter + +import ( + "github.com/sagernet/serenity/common/metadata" + "github.com/sagernet/serenity/common/semver" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" +) + +func init() { + filters = append(filters, filter190) +} + +func filter190(metadata metadata.Metadata, options *option.Options) { + if metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.9.0-alpha.1")) { + return + } + if options.DNS == nil || len(options.DNS.Rules) == 0 { + return + } + options.DNS.Rules = common.Filter(options.DNS.Rules, filter190DNSRule) +} + +func filter190DNSRule(it option.DNSRule) bool { + return !hasDNSRule([]option.DNSRule{it}, isAddressFilterRule) +} + +func isAddressFilterRule(it option.DefaultDNSRule) bool { + return len(it.GeoIP) > 0 || len(it.IPCIDR) > 0 || it.IPIsPrivate +} diff --git a/template/render_dns.go b/template/render_dns.go index 8f36564..ee1d118 100644 --- a/template/render_dns.go +++ b/template/render_dns.go @@ -94,18 +94,31 @@ func (t *Template) renderDNS(metadata M.Metadata, options *option.Options) error }, }, } + clashModeRule := t.ClashModeRule + if clashModeRule == "" { + clashModeRule = "Rule" + } + clashModeGlobal := t.ClashModeGlobal + if clashModeGlobal == "" { + clashModeGlobal = "Global" + } + clashModeDirect := t.ClashModeDirect + if clashModeDirect == "" { + clashModeDirect = "Direct" + } + if !t.DisableClashMode { options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{ Type: C.RuleTypeDefault, DefaultOptions: option.DefaultDNSRule{ - ClashMode: "Direct", - Server: DNSLocalTag, + ClashMode: clashModeGlobal, + Server: DNSDefaultTag, }, }, option.DNSRule{ Type: C.RuleTypeDefault, DefaultOptions: option.DefaultDNSRule{ - ClashMode: "Global", - Server: DNSDefaultTag, + ClashMode: clashModeDirect, + Server: DNSLocalTag, }, }) } @@ -129,6 +142,21 @@ func (t *Template) renderDNS(metadata M.Metadata, options *option.Options) error }, }) } + if !t.DisableDNSLeak && (metadata.Version != nil && metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.9.0-alpha.1"))) { + options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{ + Type: C.RuleTypeDefault, + DefaultOptions: option.DefaultDNSRule{ + ClashMode: clashModeRule, + Server: DNSDefaultTag, + }, + }, option.DNSRule{ + Type: C.RuleTypeDefault, + DefaultOptions: option.DefaultDNSRule{ + RuleSet: []string{"geoip-cn"}, + Server: DNSLocalTag, + }, + }) + } } } else { options.DNS.Rules = append(options.DNS.Rules, t.CustomDNSRules...) diff --git a/template/render_experimental.go b/template/render_experimental.go index 338f054..fc0ebd8 100644 --- a/template/render_experimental.go +++ b/template/render_experimental.go @@ -30,6 +30,9 @@ func (t *Template) renderExperimental(metadata M.Metadata, options *option.Optio CacheID: profileName, StoreFakeIP: t.EnableFakeIP, } + if !t.DisableDNSLeak && (metadata.Version != nil && metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.9.0-alpha.8"))) { + options.Experimental.CacheFile.StoreRDRC = true + } } } @@ -48,7 +51,15 @@ func (t *Template) renderExperimental(metadata M.Metadata, options *option.Optio } if !t.DisableClashMode { - options.Experimental.ClashAPI.DefaultMode = t.ClashModeRule + if !t.DisableDNSLeak && (metadata.Version != nil && metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.9.0-alpha.1"))) { + clashModeLeak := t.ClashModeLeak + if clashModeLeak == "" { + clashModeLeak = "Leak" + } + options.Experimental.ClashAPI.DefaultMode = clashModeLeak + } else { + options.Experimental.ClashAPI.DefaultMode = t.ClashModeRule + } } if t.PProfListen != "" { if options.Experimental.Debug == nil { diff --git a/template/template.go b/template/template.go index 8ed7402..f309b59 100644 --- a/template/template.go +++ b/template/template.go @@ -18,7 +18,7 @@ const ( DNSLocalSetupTag = "local_setup" DNSFakeIPTag = "remote" DefaultDNS = "tls://8.8.8.8" - DefaultDNSLocal = "114.114.114.114" + DefaultDNSLocal = "https://223.5.5.5/dns-query" DefaultDefaultTag = "Default" DefaultDirectTag = "direct" BlockTag = "block"