From 320086651c78376f9ad19143489188bd41f74be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 24 Jun 2024 09:41:00 +0800 Subject: [PATCH] Add accept empty DNS rule option --- adapter/inbound.go | 5 ++++- docs/configuration/dns/rule.md | 29 ++++++++++++++++++++++++-- docs/configuration/dns/rule.zh.md | 31 +++++++++++++++++++++++++--- docs/configuration/inbound/tun.zh.md | 12 +++++------ docs/configuration/route/rule.md | 23 ++++++++++++++++++++- docs/configuration/route/rule.zh.md | 23 ++++++++++++++++++++- option/rule.go | 25 +++++++++++++++++++--- option/rule_dns.go | 26 ++++++++++++++++++++--- route/router_dns.go | 17 +++++++++------ route/rule_default.go | 2 +- route/rule_dns.go | 2 +- route/rule_item_cidr.go | 19 +++++++++-------- route/rule_item_rule_set.go | 13 +++++++----- 13 files changed, 185 insertions(+), 42 deletions(-) diff --git a/adapter/inbound.go b/adapter/inbound.go index 063671c1..56eb5623 100644 --- a/adapter/inbound.go +++ b/adapter/inbound.go @@ -51,7 +51,9 @@ type InboundContext struct { // rule cache - IPCIDRMatchSource bool + IPCIDRMatchSource bool + IPCIDRAcceptEmpty bool + SourceAddressMatch bool SourcePortMatch bool DestinationAddressMatch bool @@ -62,6 +64,7 @@ type InboundContext struct { func (c *InboundContext) ResetRuleCache() { c.IPCIDRMatchSource = false + c.IPCIDRAcceptEmpty = false c.SourceAddressMatch = false c.SourcePortMatch = false c.DestinationAddressMatch = false diff --git a/docs/configuration/dns/rule.md b/docs/configuration/dns/rule.md index 4c4abacb..0faae0e6 100644 --- a/docs/configuration/dns/rule.md +++ b/docs/configuration/dns/rule.md @@ -2,6 +2,12 @@ icon: material/new-box --- +!!! quote "Changes in sing-box 1.10.0" + + :material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source) + :material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source) + :material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty) + !!! quote "Changes in sing-box 1.9.0" :material-plus: [geoip](#geoip) @@ -117,7 +123,10 @@ icon: material/new-box "geoip-cn", "geosite-cn" ], + // deprecated "rule_set_ipcidr_match_source": false, + "rule_set_ip_cidr_match_source": false, + "rule_set_ip_cidr_accept_empty": false, "invert": false, "outbound": [ "direct" @@ -309,7 +318,17 @@ Match [Rule Set](/configuration/route/#rule_set). !!! question "Since sing-box 1.9.0" -Make `ipcidr` in rule sets match the source IP. +!!! failure "Deprecated in sing-box 1.10.0" + + `rule_set_ipcidr_match_source` is renamed to `rule_set_ip_cidr_match_source` and will be remove in sing-box 1.11.0. + +Make `ip_cidr` rule items in rule sets match the source IP. + +#### rule_set_ip_cidr_match_source + +!!! question "Since sing-box 1.10.0" + +Make `ip_cidr` rule items in rule sets match the source IP. #### invert @@ -347,7 +366,7 @@ Will overrides `dns.client_subnet` and `servers.[].client_subnet`. ### Address Filter Fields -Only takes effect for IP address requests. When the query results do not match the address filtering rule items, the current rule will be skipped. +Only takes effect for address requests (A/AAAA/HTTPS). When the query results do not match the address filtering rule items, the current rule will be skipped. !!! info "" @@ -375,6 +394,12 @@ Match IP CIDR with query response. Match private IP with query response. +#### rule_set_ip_cidr_accept_empty + +!!! question "Since sing-box 1.10.0" + +Make `ip_cidr` rules in rule sets accept empty query response. + ### Logical Fields #### type diff --git a/docs/configuration/dns/rule.zh.md b/docs/configuration/dns/rule.zh.md index 796d29e8..eecddb38 100644 --- a/docs/configuration/dns/rule.zh.md +++ b/docs/configuration/dns/rule.zh.md @@ -2,6 +2,12 @@ icon: material/new-box --- +!!! quote "sing-box 1.10.0 中的更改" + + :material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source) + :material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source) + :material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty) + !!! quote "sing-box 1.9.0 中的更改" :material-plus: [geoip](#geoip) @@ -117,7 +123,10 @@ icon: material/new-box "geoip-cn", "geosite-cn" ], + // 已弃用 "rule_set_ipcidr_match_source": false, + "rule_set_ip_cidr_match_source": false, + "rule_set_ip_cidr_accept_empty": false, "invert": false, "outbound": [ "direct" @@ -307,7 +316,17 @@ DNS 查询类型。值可以为整数或者类型名称字符串。 !!! question "自 sing-box 1.9.0 起" -使规则集中的 `ipcidr` 规则匹配源 IP。 +!!! failure "已在 sing-box 1.10.0 废弃" + + `rule_set_ipcidr_match_source` 已重命名为 `rule_set_ip_cidr_match_source` 且将在 sing-box 1.11.0 移除。 + +使规则集中的 `ip_cidr` 规则匹配源 IP。 + +#### rule_set_ip_cidr_match_source + +!!! question "自 sing-box 1.10.0 起" + +使规则集中的 `ip_cidr` 规则匹配源 IP。 #### invert @@ -345,7 +364,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。 ### 地址筛选字段 -仅对IP地址请求生效。 当查询结果与地址筛选规则项不匹配时,将跳过当前规则。 +仅对地址请求 (A/AAAA/HTTPS) 生效。 当查询结果与地址筛选规则项不匹配时,将跳过当前规则。 !!! info "" @@ -365,7 +384,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。 !!! question "自 sing-box 1.9.0 起" -与查询相应匹配 IP CIDR。 +与查询响应匹配 IP CIDR。 #### ip_is_private @@ -373,6 +392,12 @@ DNS 查询类型。值可以为整数或者类型名称字符串。 与查询响应匹配非公开 IP。 +#### rule_set_ip_cidr_accept_empty + +!!! question "自 sing-box 1.10.0 起" + +使规则集中的 `ip_cidr` 规则接受空查询响应。 + ### 逻辑字段 #### type diff --git a/docs/configuration/inbound/tun.zh.md b/docs/configuration/inbound/tun.zh.md index bff493d4..88e02fe7 100644 --- a/docs/configuration/inbound/tun.zh.md +++ b/docs/configuration/inbound/tun.zh.md @@ -168,7 +168,7 @@ tun 接口的 IPv4 和 IPv6 前缀。 !!! failure "已在 sing-box 1.10.0 废弃" - `inet4_address` 已合并到 `address` 且将在 sing-box 1.11.0 移除. + `inet4_address` 已合并到 `address` 且将在 sing-box 1.11.0 移除。 ==必填== @@ -178,7 +178,7 @@ tun 接口的 IPv4 前缀。 !!! failure "已在 sing-box 1.10.0 废弃" - `inet6_address` 已合并到 `address` 且将在 sing-box 1.11.0 移除. + `inet6_address` 已合并到 `address` 且将在 sing-box 1.11.0 移除。 tun 接口的 IPv6 前缀。 @@ -288,7 +288,7 @@ tun 接口的 IPv6 前缀。 !!! failure "已在 sing-box 1.10.0 废弃" - `inet4_route_address` 已合并到 `route_address` 且将在 sing-box 1.11.0 移除. + `inet4_route_address` 已合并到 `route_address` 且将在 sing-box 1.11.0 移除。 启用 `auto_route` 时使用自定义路由而不是默认路由。 @@ -296,7 +296,7 @@ tun 接口的 IPv6 前缀。 !!! failure "已在 sing-box 1.10.0 废弃" - `inet6_route_address` 已合并到 `route_address` 且将在 sing-box 1.11.0 移除. + `inet6_route_address` 已合并到 `route_address` 且将在 sing-box 1.11.0 移除。 启用 `auto_route` 时使用自定义路由而不是默认路由。 @@ -310,7 +310,7 @@ tun 接口的 IPv6 前缀。 !!! failure "已在 sing-box 1.10.0 废弃" - `inet4_route_exclude_address` 已合并到 `route_exclude_address` 且将在 sing-box 1.11.0 移除. + `inet4_route_exclude_address` 已合并到 `route_exclude_address` 且将在 sing-box 1.11.0 移除。 启用 `auto_route` 时排除自定义路由。 @@ -318,7 +318,7 @@ tun 接口的 IPv6 前缀。 !!! failure "已在 sing-box 1.10.0 废弃" - `inet6_route_exclude_address` 已合并到 `route_exclude_address` 且将在 sing-box 1.11.0 移除. + `inet6_route_exclude_address` 已合并到 `route_exclude_address` 且将在 sing-box 1.11.0 移除。 启用 `auto_route` 时排除自定义路由。 diff --git a/docs/configuration/route/rule.md b/docs/configuration/route/rule.md index 62d33c6c..1d06a875 100644 --- a/docs/configuration/route/rule.md +++ b/docs/configuration/route/rule.md @@ -1,3 +1,12 @@ +--- +icon: material/alert-decagram +--- + +!!! quote "Changes in sing-box 1.10.0" + + :material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source) + :material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source) + !!! quote "Changes in sing-box 1.8.0" :material-plus: [rule_set](#rule_set) @@ -105,7 +114,9 @@ "geoip-cn", "geosite-cn" ], + // deprecated "rule_set_ipcidr_match_source": false, + "rule_set_ip_cidr_match_source": false, "invert": false, "outbound": "direct" }, @@ -303,7 +314,17 @@ Match [Rule Set](/configuration/route/#rule_set). !!! question "Since sing-box 1.8.0" -Make `ipcidr` in rule sets match the source IP. +!!! failure "Deprecated in sing-box 1.10.0" + + `rule_set_ipcidr_match_source` is renamed to `rule_set_ip_cidr_match_source` and will be remove in sing-box 1.11.0. + +Make `ip_cidr` in rule sets match the source IP. + +#### rule_set_ip_cidr_match_source + +!!! question "Since sing-box 1.10.0" + +Make `ip_cidr` in rule sets match the source IP. #### invert diff --git a/docs/configuration/route/rule.zh.md b/docs/configuration/route/rule.zh.md index cba35bc5..52d334f2 100644 --- a/docs/configuration/route/rule.zh.md +++ b/docs/configuration/route/rule.zh.md @@ -1,3 +1,12 @@ +--- +icon: material/alert-decagram +--- + +!!! quote "sing-box 1.10.0 中的更改" + + :material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source) + :material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source) + !!! quote "sing-box 1.8.0 中的更改" :material-plus: [rule_set](#rule_set) @@ -103,7 +112,9 @@ "geoip-cn", "geosite-cn" ], + // 已弃用 "rule_set_ipcidr_match_source": false, + "rule_set_ip_cidr_match_source": false, "invert": false, "outbound": "direct" }, @@ -301,7 +312,17 @@ !!! question "自 sing-box 1.8.0 起" -使规则集中的 `ipcidr` 规则匹配源 IP。 +!!! failure "已在 sing-box 1.10.0 废弃" + + `rule_set_ipcidr_match_source` 已重命名为 `rule_set_ip_cidr_match_source` 且将在 sing-box 1.11.0 移除。 + +使规则集中的 `ip_cidr` 规则匹配源 IP。 + +#### rule_set_ip_cidr_match_source + +!!! question "自 sing-box 1.10.0 起" + +使规则集中的 `ip_cidr` 规则匹配源 IP。 #### invert diff --git a/option/rule.go b/option/rule.go index 0ea133c7..74dd13c6 100644 --- a/option/rule.go +++ b/option/rule.go @@ -64,7 +64,7 @@ func (r Rule) IsValid() bool { } } -type DefaultRule struct { +type _DefaultRule struct { Inbound Listable[string] `json:"inbound,omitempty"` IPVersion int `json:"ip_version,omitempty"` Network Listable[string] `json:"network,omitempty"` @@ -94,12 +94,31 @@ type DefaultRule struct { WIFISSID Listable[string] `json:"wifi_ssid,omitempty"` WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"` RuleSet Listable[string] `json:"rule_set,omitempty"` - RuleSetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"` + RuleSetIPCIDRMatchSource bool `json:"rule_set_ip_cidr_match_source,omitempty"` Invert bool `json:"invert,omitempty"` Outbound string `json:"outbound,omitempty"` + + // Deprecated: renamed to rule_set_ip_cidr_match_source + Deprecated_RulesetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"` } -func (r DefaultRule) IsValid() bool { +type DefaultRule _DefaultRule + +func (r *DefaultRule) UnmarshalJSON(bytes []byte) error { + err := json.Unmarshal(bytes, (*_DefaultRule)(r)) + if err != nil { + return err + } + //nolint:staticcheck + //goland:noinspection GoDeprecation + if r.Deprecated_RulesetIPCIDRMatchSource { + r.Deprecated_RulesetIPCIDRMatchSource = false + r.RuleSetIPCIDRMatchSource = true + } + return nil +} + +func (r *DefaultRule) IsValid() bool { var defaultValue DefaultRule defaultValue.Invert = r.Invert defaultValue.Outbound = r.Outbound diff --git a/option/rule_dns.go b/option/rule_dns.go index c5994e1c..2afe245e 100644 --- a/option/rule_dns.go +++ b/option/rule_dns.go @@ -64,7 +64,7 @@ func (r DNSRule) IsValid() bool { } } -type DefaultDNSRule struct { +type _DefaultDNSRule struct { Inbound Listable[string] `json:"inbound,omitempty"` IPVersion int `json:"ip_version,omitempty"` QueryType Listable[DNSQueryType] `json:"query_type,omitempty"` @@ -96,15 +96,35 @@ type DefaultDNSRule struct { WIFISSID Listable[string] `json:"wifi_ssid,omitempty"` WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"` RuleSet Listable[string] `json:"rule_set,omitempty"` - RuleSetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"` + RuleSetIPCIDRMatchSource bool `json:"rule_set_ip_cidr_match_source,omitempty"` + RuleSetIPCIDRAcceptEmpty bool `json:"rule_set_ip_cidr_accept_empty,omitempty"` Invert bool `json:"invert,omitempty"` Server string `json:"server,omitempty"` DisableCache bool `json:"disable_cache,omitempty"` RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"` ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"` + + // Deprecated: renamed to rule_set_ip_cidr_match_source + Deprecated_RulesetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"` } -func (r DefaultDNSRule) IsValid() bool { +type DefaultDNSRule _DefaultDNSRule + +func (r *DefaultDNSRule) UnmarshalJSON(bytes []byte) error { + err := json.UnmarshalDisallowUnknownFields(bytes, (*_DefaultDNSRule)(r)) + if err != nil { + return err + } + //nolint:staticcheck + //goland:noinspection GoDeprecation + if r.Deprecated_RulesetIPCIDRMatchSource { + r.Deprecated_RulesetIPCIDRMatchSource = false + r.RuleSetIPCIDRMatchSource = true + } + return nil +} + +func (r *DefaultDNSRule) IsValid() bool { var defaultValue DefaultDNSRule defaultValue.Invert = r.Invert defaultValue.Server = r.Server diff --git a/route/router_dns.go b/route/router_dns.go index 51994072..ead8c289 100644 --- a/route/router_dns.go +++ b/route/router_dns.go @@ -104,7 +104,8 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, er response, cached = r.dnsClient.ExchangeCache(ctx, message) if !cached { var metadata *adapter.InboundContext - ctx, metadata = adapter.AppendContext(ctx) + ctx, metadata = adapter.ExtendContext(ctx) + metadata.Destination = M.Socksaddr{} if len(message.Question) > 0 { metadata.QueryType = message.Question[0].Qtype switch metadata.QueryType { @@ -126,12 +127,16 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, er dnsCtx context.Context addressLimit bool ) - dnsCtx, transport, strategy, rule, ruleIndex = r.matchDNS(ctx, true, ruleIndex, isAddressQuery(message)) + dnsCtx = adapter.OverrideContext(dnsCtx) if rule != nil && rule.WithAddressLimit() { addressLimit = true response, err = r.dnsClient.ExchangeWithResponseCheck(dnsCtx, transport, message, strategy, func(response *mDNS.Msg) bool { - metadata.DestinationAddresses, _ = dns.MessageToAddresses(response) + addresses, addrErr := dns.MessageToAddresses(response) + if addrErr != nil { + return false + } + metadata.DestinationAddresses = addresses return rule.MatchAddressLimit(metadata) }) } else { @@ -190,7 +195,8 @@ func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainS return responseAddrs, nil } r.dnsLogger.DebugContext(ctx, "lookup domain ", domain) - ctx, metadata := adapter.AppendContext(ctx) + ctx, metadata := adapter.ExtendContext(ctx) + metadata.Destination = M.Socksaddr{} metadata.Domain = domain var ( transport dns.Transport @@ -204,9 +210,8 @@ func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainS dnsCtx context.Context addressLimit bool ) - metadata.ResetRuleCache() - metadata.DestinationAddresses = nil dnsCtx, transport, transportStrategy, rule, ruleIndex = r.matchDNS(ctx, false, ruleIndex, true) + dnsCtx = adapter.OverrideContext(dnsCtx) if strategy == dns.DomainStrategyAsIS { strategy = transportStrategy } diff --git a/route/rule_default.go b/route/rule_default.go index d1d13f7d..53e53bdf 100644 --- a/route/rule_default.go +++ b/route/rule_default.go @@ -205,7 +205,7 @@ func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options opt rule.allItems = append(rule.allItems, item) } if len(options.RuleSet) > 0 { - item := NewRuleSetItem(router, options.RuleSet, options.RuleSetIPCIDRMatchSource) + item := NewRuleSetItem(router, options.RuleSet, options.RuleSetIPCIDRMatchSource, false) rule.items = append(rule.items, item) rule.allItems = append(rule.allItems, item) } diff --git a/route/rule_dns.go b/route/rule_dns.go index 955526fc..1b79d30b 100644 --- a/route/rule_dns.go +++ b/route/rule_dns.go @@ -219,7 +219,7 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options rule.allItems = append(rule.allItems, item) } if len(options.RuleSet) > 0 { - item := NewRuleSetItem(router, options.RuleSet, options.RuleSetIPCIDRMatchSource) + item := NewRuleSetItem(router, options.RuleSet, options.RuleSetIPCIDRMatchSource, options.RuleSetIPCIDRAcceptEmpty) rule.items = append(rule.items, item) rule.allItems = append(rule.allItems, item) } diff --git a/route/rule_item_cidr.go b/route/rule_item_cidr.go index 85b9c8d7..be0bb136 100644 --- a/route/rule_item_cidr.go +++ b/route/rule_item_cidr.go @@ -75,18 +75,19 @@ func NewRawIPCIDRItem(isSource bool, ipSet *netipx.IPSet) *IPCIDRItem { func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool { if r.isSource || metadata.IPCIDRMatchSource { return r.ipSet.Contains(metadata.Source.Addr) - } else { - if metadata.Destination.IsIP() { - return r.ipSet.Contains(metadata.Destination.Addr) - } else { - for _, address := range metadata.DestinationAddresses { - if r.ipSet.Contains(address) { - return true - } + } + if metadata.Destination.IsIP() { + return r.ipSet.Contains(metadata.Destination.Addr) + } + if len(metadata.DestinationAddresses) > 0 { + for _, address := range metadata.DestinationAddresses { + if r.ipSet.Contains(address) { + return true } } + return false } - return false + return metadata.IPCIDRAcceptEmpty } func (r *IPCIDRItem) String() string { diff --git a/route/rule_item_rule_set.go b/route/rule_item_rule_set.go index 4ecf8c18..b80fca99 100644 --- a/route/rule_item_rule_set.go +++ b/route/rule_item_rule_set.go @@ -15,14 +15,16 @@ type RuleSetItem struct { router adapter.Router tagList []string setList []adapter.RuleSet - ipcidrMatchSource bool + ipCidrMatchSource bool + ipCidrAcceptEmpty bool } -func NewRuleSetItem(router adapter.Router, tagList []string, ipCIDRMatchSource bool) *RuleSetItem { +func NewRuleSetItem(router adapter.Router, tagList []string, ipCIDRMatchSource bool, ipCidrAcceptEmpty bool) *RuleSetItem { return &RuleSetItem{ router: router, tagList: tagList, - ipcidrMatchSource: ipCIDRMatchSource, + ipCidrMatchSource: ipCIDRMatchSource, + ipCidrAcceptEmpty: ipCidrAcceptEmpty, } } @@ -39,7 +41,8 @@ func (r *RuleSetItem) Start() error { } func (r *RuleSetItem) Match(metadata *adapter.InboundContext) bool { - metadata.IPCIDRMatchSource = r.ipcidrMatchSource + metadata.IPCIDRMatchSource = r.ipCidrMatchSource + metadata.IPCIDRAcceptEmpty = r.ipCidrAcceptEmpty for _, ruleSet := range r.setList { if ruleSet.Match(metadata) { return true @@ -49,7 +52,7 @@ func (r *RuleSetItem) Match(metadata *adapter.InboundContext) bool { } func (r *RuleSetItem) ContainsDestinationIPCIDRRule() bool { - if r.ipcidrMatchSource { + if r.ipCidrMatchSource { return false } return common.Any(r.setList, func(ruleSet adapter.RuleSet) bool {