skipped 3 lines 4 4 "context" 5 5 "net/netip" 6 6 "strings" 7 + "time" 7 8 8 9 "github.com/sagernet/sing-box/adapter" 9 10 C "github.com/sagernet/sing-box/constant" 10 11 "github.com/sagernet/sing-box/log" 11 12 "github.com/sagernet/sing-dns" 13 + "github.com/sagernet/sing/common/cache" 12 14 E "github.com/sagernet/sing/common/exceptions" 13 15 F "github.com/sagernet/sing/common/format" 16 + M "github.com/sagernet/sing/common/metadata" 14 17 15 18 mDNS "github.com/miekg/dns" 16 19 ) 20 + 21 + type DNSReverseMapping struct { 22 + cache *cache.LruCache[netip.Addr, string] 23 + } 24 + 25 + func NewDNSReverseMapping() *DNSReverseMapping { 26 + return &DNSReverseMapping{ 27 + cache: cache.New[netip.Addr, string](), 28 + } 29 + } 30 + 31 + func (m *DNSReverseMapping) Save(address netip.Addr, domain string, ttl int) { 32 + m.cache.StoreWithExpire(address, domain, time.Now().Add(time.Duration(ttl)*time.Second)) 33 + } 34 + 35 + func (m *DNSReverseMapping) Query(address netip.Addr) (string, bool) { 36 + domain, loaded := m.cache.Load(address) 37 + return domain, loaded 38 + } 17 39 18 40 func (r *Router) matchDNS(ctx context.Context) (context.Context, dns.Transport, dns.DomainStrategy) { 19 41 metadata := adapter.ContextFrom(ctx) skipped 48 lines 68 90 } 69 91 if len(message.Question) > 0 && response != nil { 70 92 LogDNSAnswers(r.dnsLogger, ctx, message.Question[0].Name, response.Answer) 93 + } 94 + if r.dnsReverseMapping != nil && len(message.Question) > 0 && response != nil && len(response.Answer) > 0 { 95 + for _, answer := range response.Answer { 96 + switch record := answer.(type) { 97 + case *mDNS.A: 98 + r.dnsReverseMapping.Save(M.AddrFromIP(record.A), fqdnToDomain(record.Hdr.Name), int(record.Hdr.Ttl)) 99 + case *mDNS.AAAA: 100 + r.dnsReverseMapping.Save(M.AddrFromIP(record.AAAA), fqdnToDomain(record.Hdr.Name), int(record.Hdr.Ttl)) 101 + } 102 + } 71 103 } 72 104 return response, err 73 105 } skipped 51 lines