Add query_client_subnet and query_dnssec DNS rule items and remove_client_subnet DNS route action option

This commit is contained in:
世界
2026-08-30 17:41:45 +08:00
parent 4e91d92c5f
commit b3a45e0839
16 changed files with 297 additions and 15 deletions
+12 -6
View File
@@ -107,12 +107,15 @@ func (k dnsCacheKey) persistentName() string {
}
func (c *Client) newCacheKey(transport adapter.DNSTransport, question dns.Question, message *dns.Msg, options adapter.DNSQueryOptions) dnsCacheKey {
clientSubnet := options.ClientSubnet
if !clientSubnet.IsValid() {
clientSubnet = c.clientSubnet
}
if !clientSubnet.IsValid() {
clientSubnet = clientSubnetFromMessage(message)
var clientSubnet netip.Prefix
if !options.RemoveClientSubnet {
clientSubnet = options.ClientSubnet
if !clientSubnet.IsValid() {
clientSubnet = c.clientSubnet
}
if !clientSubnet.IsValid() {
clientSubnet = clientSubnetFromMessage(message)
}
}
return dnsCacheKey{
Question: question,
@@ -679,6 +682,9 @@ func (c *Client) backgroundRefreshDNS(transport adapter.DNSTransport, key dnsCac
}
func (c *Client) prepareExchangeMessage(message *dns.Msg, options adapter.DNSQueryOptions) *dns.Msg {
if options.RemoveClientSubnet {
return removeClientSubnet(message)
}
clientSubnet := options.ClientSubnet
if !clientSubnet.IsValid() {
clientSubnet = c.clientSubnet
+29 -1
View File
@@ -2,6 +2,9 @@ package dns
import (
"net/netip"
"slices"
"github.com/sagernet/sing/common"
"github.com/miekg/dns"
)
@@ -25,12 +28,37 @@ func clientSubnetFromMessage(message *dns.Msg) netip.Prefix {
if !addressLoaded {
return netip.Prefix{}
}
return netip.PrefixFrom(address, int(subnetOption.SourceNetmask))
return netip.PrefixFrom(address.Unmap(), int(subnetOption.SourceNetmask))
}
}
return netip.Prefix{}
}
func removeClientSubnet(message *dns.Msg) *dns.Msg {
if !slices.ContainsFunc(message.Extra, func(record dns.RR) bool {
optRecord, isOPTRecord := record.(*dns.OPT)
if !isOPTRecord {
return false
}
return slices.ContainsFunc(optRecord.Option, func(option dns.EDNS0) bool {
return option.Option() == dns.EDNS0SUBNET
})
}) {
return message
}
message = message.Copy()
for _, record := range message.Extra {
optRecord, isOPTRecord := record.(*dns.OPT)
if !isOPTRecord {
continue
}
optRecord.Option = common.Filter(optRecord.Option, func(option dns.EDNS0) bool {
return option.Option() != dns.EDNS0SUBNET
})
}
return message
}
func setClientSubnet(message *dns.Msg, clientSubnet netip.Prefix, clone bool) *dns.Msg {
var (
optRecord *dns.OPT
+20
View File
@@ -326,6 +326,11 @@ func (r *Router) matchDNS(ctx context.Context, rules []adapter.DNSRule, allowFak
}
if action.ClientSubnet.IsValid() {
options.ClientSubnet = action.ClientSubnet
options.RemoveClientSubnet = false
}
if action.RemoveClientSubnet {
options.ClientSubnet = netip.Prefix{}
options.RemoveClientSubnet = true
}
return transport, currentRule, currentRuleIndex
case *R.RuleActionDNSRouteOptions:
@@ -343,6 +348,11 @@ func (r *Router) matchDNS(ctx context.Context, rules []adapter.DNSRule, allowFak
}
if action.ClientSubnet.IsValid() {
options.ClientSubnet = action.ClientSubnet
options.RemoveClientSubnet = false
}
if action.RemoveClientSubnet {
options.ClientSubnet = netip.Prefix{}
options.RemoveClientSubnet = true
}
case *R.RuleActionReject:
return nil, currentRule, currentRuleIndex
@@ -373,6 +383,11 @@ func (r *Router) applyDNSRouteOptions(options *adapter.DNSQueryOptions, routeOpt
}
if routeOptions.ClientSubnet.IsValid() {
options.ClientSubnet = routeOptions.ClientSubnet
options.RemoveClientSubnet = false
}
if routeOptions.RemoveClientSubnet {
options.ClientSubnet = netip.Prefix{}
options.RemoveClientSubnet = true
}
}
@@ -945,6 +960,8 @@ func (r *Router) resolveLookupStrategy(options adapter.DNSQueryOptions) C.Domain
func withLookupQueryMetadata(ctx context.Context, qType uint16) context.Context {
ctx, metadata := adapter.ExtendContext(ctx)
metadata.QueryType = qType
metadata.QueryClientSubnet = netip.Prefix{}
metadata.QueryDNSSEC = false
metadata.IPVersion = 0
switch qType {
case mDNS.TypeA:
@@ -1069,6 +1086,9 @@ func (r *Router) prepareExchange(ctx context.Context, message *mDNS.Msg) (*dnsEx
metadata.IPVersion = 6
}
metadata.Domain = FqdnToDomain(message.Question[0].Name)
metadata.QueryClientSubnet = clientSubnetFromMessage(message)
edns0Option := message.IsEdns0()
metadata.QueryDNSSEC = edns0Option != nil && edns0Option.Do()
return &dnsExchangeContext{
ctx: ctx,
rules: rules,