mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-15 21:00:27 +00:00
Add query_client_subnet and query_dnssec DNS rule items and remove_client_subnet DNS route action option
This commit is contained in:
@@ -139,6 +139,7 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
|
||||
DisableOptimisticCache: action.RouteOptions.DisableOptimisticCache,
|
||||
RewriteTTL: action.RouteOptions.RewriteTTL,
|
||||
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptions.ClientSubnet)),
|
||||
RemoveClientSubnet: action.RouteOptions.RemoveClientSubnet,
|
||||
},
|
||||
}
|
||||
case C.RuleActionTypeEvaluate:
|
||||
@@ -153,6 +154,7 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
|
||||
DisableOptimisticCache: action.EvaluateOptions.DisableOptimisticCache,
|
||||
RewriteTTL: action.EvaluateOptions.RewriteTTL,
|
||||
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.EvaluateOptions.ClientSubnet)),
|
||||
RemoveClientSubnet: action.EvaluateOptions.RemoveClientSubnet,
|
||||
},
|
||||
}
|
||||
case C.RuleActionTypeRespond:
|
||||
@@ -165,6 +167,7 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
|
||||
DisableOptimisticCache: action.RouteOptionsOptions.DisableOptimisticCache,
|
||||
RewriteTTL: action.RouteOptionsOptions.RewriteTTL,
|
||||
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptionsOptions.ClientSubnet)),
|
||||
RemoveClientSubnet: action.RouteOptionsOptions.RemoveClientSubnet,
|
||||
}
|
||||
case C.RuleActionTypeReject:
|
||||
return &RuleActionReject{
|
||||
@@ -349,6 +352,9 @@ func formatDNSRouteAction(action string, server string, speculative bool, option
|
||||
if options.ClientSubnet.IsValid() {
|
||||
descriptions = append(descriptions, F.ToString("client-subnet=", options.ClientSubnet))
|
||||
}
|
||||
if options.RemoveClientSubnet {
|
||||
descriptions = append(descriptions, "remove-client-subnet")
|
||||
}
|
||||
return F.ToString(action, "(", strings.Join(descriptions, ","), ")")
|
||||
}
|
||||
|
||||
@@ -359,6 +365,7 @@ type RuleActionDNSRouteOptions struct {
|
||||
DisableOptimisticCache bool
|
||||
RewriteTTL *uint32
|
||||
ClientSubnet netip.Prefix
|
||||
RemoveClientSubnet bool
|
||||
}
|
||||
|
||||
func (r *RuleActionDNSRouteOptions) Type() string {
|
||||
@@ -382,6 +389,9 @@ func (r *RuleActionDNSRouteOptions) String() string {
|
||||
if r.ClientSubnet.IsValid() {
|
||||
descriptions = append(descriptions, F.ToString("client-subnet=", r.ClientSubnet))
|
||||
}
|
||||
if r.RemoveClientSubnet {
|
||||
descriptions = append(descriptions, "remove-client-subnet")
|
||||
}
|
||||
return F.ToString("route-options(", strings.Join(descriptions, ","), ")")
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,18 @@ func validateDNSRuleAction(action option.DNSRuleAction) error {
|
||||
if action.Action == C.RuleActionTypeReject && action.RejectOptions.Method == C.RuleActionRejectMethodReply {
|
||||
return E.New("reject method `reply` is not supported for DNS rules")
|
||||
}
|
||||
var routeOptions option.AbstractDNSRouteActionOptions
|
||||
switch action.Action {
|
||||
case "", C.RuleActionTypeRoute:
|
||||
routeOptions = action.RouteOptions.AbstractDNSRouteActionOptions
|
||||
case C.RuleActionTypeEvaluate:
|
||||
routeOptions = action.EvaluateOptions.AbstractDNSRouteActionOptions
|
||||
case C.RuleActionTypeRouteOptions:
|
||||
routeOptions = option.AbstractDNSRouteActionOptions(action.RouteOptionsOptions)
|
||||
}
|
||||
if routeOptions.RemoveClientSubnet && routeOptions.ClientSubnet != nil {
|
||||
return E.New("`client_subnet` and `remove_client_subnet` are mutually exclusive")
|
||||
}
|
||||
if action.Race {
|
||||
switch action.Action {
|
||||
case "", C.RuleActionTypeRoute, C.RuleActionTypeRespond, C.RuleActionTypeReject, C.RuleActionTypePredefined:
|
||||
@@ -127,6 +139,16 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.QueryClientSubnet) > 0 {
|
||||
item := NewQueryClientSubnetItem(options.QueryClientSubnet)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if options.QueryDNSSEC {
|
||||
item := NewQueryDNSSECItem()
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.Network) > 0 {
|
||||
item := NewNetworkItem(options.Network)
|
||||
rule.items = append(rule.items, item)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package rule
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
)
|
||||
|
||||
var _ RuleItem = (*QueryClientSubnetItem)(nil)
|
||||
|
||||
type QueryClientSubnetItem struct {
|
||||
prefixes []netip.Prefix
|
||||
}
|
||||
|
||||
func NewQueryClientSubnetItem(prefixables badoption.Listable[*badoption.Prefixable]) *QueryClientSubnetItem {
|
||||
return &QueryClientSubnetItem{
|
||||
prefixes: common.Map(prefixables, func(it *badoption.Prefixable) netip.Prefix {
|
||||
return it.Build(netip.Prefix{})
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *QueryClientSubnetItem) Match(metadata *adapter.InboundContext) bool {
|
||||
clientSubnet := metadata.QueryClientSubnet
|
||||
if !clientSubnet.IsValid() {
|
||||
return false
|
||||
}
|
||||
return slices.ContainsFunc(r.prefixes, func(prefix netip.Prefix) bool {
|
||||
return clientSubnet.Bits() >= prefix.Bits() && prefix.Contains(clientSubnet.Addr())
|
||||
})
|
||||
}
|
||||
|
||||
func (r *QueryClientSubnetItem) String() string {
|
||||
if len(r.prefixes) == 1 {
|
||||
return "query_client_subnet=" + r.prefixes[0].String()
|
||||
}
|
||||
return "query_client_subnet=[" + strings.Join(common.Map(r.prefixes, netip.Prefix.String), " ") + "]"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package rule
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
)
|
||||
|
||||
var _ RuleItem = (*QueryDNSSECItem)(nil)
|
||||
|
||||
type QueryDNSSECItem struct{}
|
||||
|
||||
func NewQueryDNSSECItem() *QueryDNSSECItem {
|
||||
return &QueryDNSSECItem{}
|
||||
}
|
||||
|
||||
func (r *QueryDNSSECItem) Match(metadata *adapter.InboundContext) bool {
|
||||
return metadata.QueryDNSSEC
|
||||
}
|
||||
|
||||
func (r *QueryDNSSECItem) String() string {
|
||||
return "query_dnssec=true"
|
||||
}
|
||||
Reference in New Issue
Block a user