client.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. package dns
  2. import (
  3. "context"
  4. "errors"
  5. "net"
  6. "net/netip"
  7. "time"
  8. "github.com/sagernet/sing-box/adapter"
  9. "github.com/sagernet/sing-box/common/compatible"
  10. C "github.com/sagernet/sing-box/constant"
  11. "github.com/sagernet/sing/common"
  12. E "github.com/sagernet/sing/common/exceptions"
  13. "github.com/sagernet/sing/common/logger"
  14. "github.com/sagernet/sing/common/task"
  15. "github.com/sagernet/sing/contrab/freelru"
  16. "github.com/sagernet/sing/contrab/maphash"
  17. "github.com/miekg/dns"
  18. )
  19. var (
  20. ErrNoRawSupport = E.New("no raw query support by current transport")
  21. ErrNotCached = E.New("not cached")
  22. ErrResponseRejected = E.New("response rejected")
  23. ErrResponseRejectedCached = E.Extend(ErrResponseRejected, "cached")
  24. )
  25. var _ adapter.DNSClient = (*Client)(nil)
  26. type Client struct {
  27. ctx context.Context
  28. timeout time.Duration
  29. disableCache bool
  30. disableExpire bool
  31. optimisticTimeout time.Duration
  32. cacheCapacity uint32
  33. clientSubnet netip.Prefix
  34. rdrc adapter.RDRCStore
  35. initRDRCFunc func() adapter.RDRCStore
  36. dnsCache adapter.DNSCacheStore
  37. initDNSCacheFunc func() adapter.DNSCacheStore
  38. logger logger.ContextLogger
  39. cache freelru.Cache[dnsCacheKey, *dns.Msg]
  40. cacheLock compatible.Map[dnsCacheKey, chan struct{}]
  41. backgroundRefresh compatible.Map[dnsCacheKey, struct{}]
  42. }
  43. type ClientOptions struct {
  44. Context context.Context
  45. Timeout time.Duration
  46. DisableCache bool
  47. DisableExpire bool
  48. OptimisticTimeout time.Duration
  49. CacheCapacity uint32
  50. ClientSubnet netip.Prefix
  51. RDRC func() adapter.RDRCStore
  52. DNSCache func() adapter.DNSCacheStore
  53. Logger logger.ContextLogger
  54. }
  55. func NewClient(options ClientOptions) *Client {
  56. cacheCapacity := options.CacheCapacity
  57. if cacheCapacity < 1024 {
  58. cacheCapacity = 1024
  59. }
  60. client := &Client{
  61. ctx: options.Context,
  62. timeout: options.Timeout,
  63. disableCache: options.DisableCache,
  64. disableExpire: options.DisableExpire,
  65. optimisticTimeout: options.OptimisticTimeout,
  66. cacheCapacity: cacheCapacity,
  67. clientSubnet: options.ClientSubnet,
  68. initRDRCFunc: options.RDRC,
  69. initDNSCacheFunc: options.DNSCache,
  70. logger: options.Logger,
  71. }
  72. if client.timeout == 0 {
  73. client.timeout = C.DNSTimeout
  74. }
  75. if !client.disableCache && client.initDNSCacheFunc == nil {
  76. client.initializeMemoryCache()
  77. }
  78. return client
  79. }
  80. type dnsCacheKey struct {
  81. dns.Question
  82. transportTag string
  83. }
  84. func (c *Client) Start() {
  85. if c.initRDRCFunc != nil {
  86. c.rdrc = c.initRDRCFunc()
  87. }
  88. if c.initDNSCacheFunc != nil {
  89. c.dnsCache = c.initDNSCacheFunc()
  90. }
  91. if c.dnsCache == nil {
  92. c.initializeMemoryCache()
  93. }
  94. }
  95. func (c *Client) initializeMemoryCache() {
  96. if c.disableCache || c.cache != nil {
  97. return
  98. }
  99. c.cache = common.Must1(freelru.NewSharded[dnsCacheKey, *dns.Msg](c.cacheCapacity, maphash.NewHasher[dnsCacheKey]().Hash32))
  100. }
  101. func extractNegativeTTL(response *dns.Msg) (uint32, bool) {
  102. for _, record := range response.Ns {
  103. if soa, isSOA := record.(*dns.SOA); isSOA {
  104. soaTTL := soa.Header().Ttl
  105. soaMinimum := soa.Minttl
  106. if soaTTL < soaMinimum {
  107. return soaTTL, true
  108. }
  109. return soaMinimum, true
  110. }
  111. }
  112. return 0, false
  113. }
  114. func computeTimeToLive(response *dns.Msg) uint32 {
  115. var timeToLive uint32
  116. if len(response.Answer) == 0 {
  117. if soaTTL, hasSOA := extractNegativeTTL(response); hasSOA {
  118. return soaTTL
  119. }
  120. }
  121. for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
  122. for _, record := range recordList {
  123. if record.Header().Rrtype == dns.TypeOPT {
  124. continue
  125. }
  126. if timeToLive == 0 || record.Header().Ttl > 0 && record.Header().Ttl < timeToLive {
  127. timeToLive = record.Header().Ttl
  128. }
  129. }
  130. }
  131. return timeToLive
  132. }
  133. func normalizeTTL(response *dns.Msg, timeToLive uint32) {
  134. for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
  135. for _, record := range recordList {
  136. if record.Header().Rrtype == dns.TypeOPT {
  137. continue
  138. }
  139. record.Header().Ttl = timeToLive
  140. }
  141. }
  142. }
  143. func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg, options adapter.DNSQueryOptions, responseChecker func(response *dns.Msg) bool) (*dns.Msg, error) {
  144. if len(message.Question) == 0 {
  145. if c.logger != nil {
  146. c.logger.WarnContext(ctx, "bad question size: ", len(message.Question))
  147. }
  148. return FixedResponseStatus(message, dns.RcodeFormatError), nil
  149. }
  150. question := message.Question[0]
  151. if question.Qtype == dns.TypeA && options.Strategy == C.DomainStrategyIPv6Only || question.Qtype == dns.TypeAAAA && options.Strategy == C.DomainStrategyIPv4Only {
  152. if c.logger != nil {
  153. c.logger.DebugContext(ctx, "strategy rejected")
  154. }
  155. return FixedResponseStatus(message, dns.RcodeSuccess), nil
  156. }
  157. message = c.prepareExchangeMessage(message, options)
  158. isSimpleRequest := len(message.Question) == 1 &&
  159. len(message.Ns) == 0 &&
  160. (len(message.Extra) == 0 || len(message.Extra) == 1 &&
  161. message.Extra[0].Header().Rrtype == dns.TypeOPT &&
  162. message.Extra[0].Header().Class > 0 &&
  163. message.Extra[0].Header().Ttl == 0 &&
  164. len(message.Extra[0].(*dns.OPT).Option) == 0) &&
  165. !options.ClientSubnet.IsValid()
  166. disableCache := !isSimpleRequest || c.disableCache || options.DisableCache
  167. if !disableCache {
  168. cacheKey := dnsCacheKey{Question: question, transportTag: transport.Tag()}
  169. cond, loaded := c.cacheLock.LoadOrStore(cacheKey, make(chan struct{}))
  170. if loaded {
  171. select {
  172. case <-cond:
  173. case <-ctx.Done():
  174. return nil, ctx.Err()
  175. }
  176. } else {
  177. defer func() {
  178. c.cacheLock.Delete(cacheKey)
  179. close(cond)
  180. }()
  181. }
  182. response, ttl, isStale := c.loadResponse(question, transport)
  183. if response != nil {
  184. if isStale && !options.DisableOptimisticCache {
  185. c.backgroundRefreshDNS(transport, question, message.Copy(), options, responseChecker)
  186. logOptimisticResponse(c.logger, ctx, response)
  187. response.Id = message.Id
  188. return response, nil
  189. } else if !isStale {
  190. logCachedResponse(c.logger, ctx, response, ttl)
  191. response.Id = message.Id
  192. return response, nil
  193. }
  194. }
  195. }
  196. messageId := message.Id
  197. contextTransport, clientSubnetLoaded := transportTagFromContext(ctx)
  198. if clientSubnetLoaded && transport.Tag() == contextTransport {
  199. return nil, E.New("DNS query loopback in transport[", contextTransport, "]")
  200. }
  201. ctx = contextWithTransportTag(ctx, transport.Tag())
  202. if !disableCache && responseChecker != nil && c.rdrc != nil {
  203. rejected := c.rdrc.LoadRDRC(transport.Tag(), question.Name, question.Qtype)
  204. if rejected {
  205. return nil, ErrResponseRejectedCached
  206. }
  207. }
  208. response, err := c.exchangeToTransport(ctx, transport, message)
  209. if err != nil {
  210. return nil, err
  211. }
  212. disableCache = disableCache || (response.Rcode != dns.RcodeSuccess && response.Rcode != dns.RcodeNameError)
  213. if responseChecker != nil {
  214. var rejected bool
  215. if response.Rcode != dns.RcodeSuccess && response.Rcode != dns.RcodeNameError {
  216. rejected = true
  217. } else {
  218. rejected = !responseChecker(response)
  219. }
  220. if rejected {
  221. if !disableCache && c.rdrc != nil {
  222. c.rdrc.SaveRDRCAsync(transport.Tag(), question.Name, question.Qtype, c.logger)
  223. }
  224. logRejectedResponse(c.logger, ctx, response)
  225. return response, ErrResponseRejected
  226. }
  227. }
  228. timeToLive := applyResponseOptions(question, response, options)
  229. if !disableCache {
  230. c.storeCache(transport, question, response, timeToLive)
  231. }
  232. response.Id = messageId
  233. requestEDNSOpt := message.IsEdns0()
  234. responseEDNSOpt := response.IsEdns0()
  235. if responseEDNSOpt != nil && (requestEDNSOpt == nil || requestEDNSOpt.Version() < responseEDNSOpt.Version()) {
  236. response.Extra = common.Filter(response.Extra, func(it dns.RR) bool {
  237. return it.Header().Rrtype != dns.TypeOPT
  238. })
  239. if requestEDNSOpt != nil {
  240. response.SetEdns0(responseEDNSOpt.UDPSize(), responseEDNSOpt.Do())
  241. }
  242. }
  243. logExchangedResponse(c.logger, ctx, response, timeToLive)
  244. return response, nil
  245. }
  246. func (c *Client) Lookup(ctx context.Context, transport adapter.DNSTransport, domain string, options adapter.DNSQueryOptions, responseChecker func(response *dns.Msg) bool) ([]netip.Addr, error) {
  247. domain = FqdnToDomain(domain)
  248. dnsName := dns.Fqdn(domain)
  249. var strategy C.DomainStrategy
  250. if options.LookupStrategy != C.DomainStrategyAsIS {
  251. strategy = options.LookupStrategy
  252. } else {
  253. strategy = options.Strategy
  254. }
  255. lookupOptions := options
  256. if options.LookupStrategy != C.DomainStrategyAsIS {
  257. lookupOptions.Strategy = strategy
  258. }
  259. if strategy == C.DomainStrategyIPv4Only {
  260. return c.lookupToExchange(ctx, transport, dnsName, dns.TypeA, lookupOptions, responseChecker)
  261. } else if strategy == C.DomainStrategyIPv6Only {
  262. return c.lookupToExchange(ctx, transport, dnsName, dns.TypeAAAA, lookupOptions, responseChecker)
  263. }
  264. var response4 []netip.Addr
  265. var response6 []netip.Addr
  266. var group task.Group
  267. group.Append("exchange4", func(ctx context.Context) error {
  268. response, err := c.lookupToExchange(ctx, transport, dnsName, dns.TypeA, lookupOptions, responseChecker)
  269. if err != nil {
  270. return err
  271. }
  272. response4 = response
  273. return nil
  274. })
  275. group.Append("exchange6", func(ctx context.Context) error {
  276. response, err := c.lookupToExchange(ctx, transport, dnsName, dns.TypeAAAA, lookupOptions, responseChecker)
  277. if err != nil {
  278. return err
  279. }
  280. response6 = response
  281. return nil
  282. })
  283. err := group.Run(ctx)
  284. if len(response4) == 0 && len(response6) == 0 {
  285. return nil, err
  286. }
  287. return sortAddresses(response4, response6, strategy), nil
  288. }
  289. func (c *Client) ClearCache() {
  290. if c.cache != nil {
  291. c.cache.Purge()
  292. }
  293. if c.dnsCache != nil {
  294. err := c.dnsCache.ClearDNSCache()
  295. if err != nil && c.logger != nil {
  296. c.logger.Warn("clear DNS cache: ", err)
  297. }
  298. }
  299. }
  300. func sortAddresses(response4 []netip.Addr, response6 []netip.Addr, strategy C.DomainStrategy) []netip.Addr {
  301. if strategy == C.DomainStrategyPreferIPv6 {
  302. return append(response6, response4...)
  303. } else {
  304. return append(response4, response6...)
  305. }
  306. }
  307. func (c *Client) storeCache(transport adapter.DNSTransport, question dns.Question, message *dns.Msg, timeToLive uint32) {
  308. if timeToLive == 0 {
  309. return
  310. }
  311. if c.dnsCache != nil {
  312. packed, err := message.Pack()
  313. if err == nil {
  314. expireAt := time.Now().Add(time.Second * time.Duration(timeToLive))
  315. c.dnsCache.SaveDNSCacheAsync(transport.Tag(), question.Name, question.Qtype, packed, expireAt, c.logger)
  316. }
  317. return
  318. }
  319. if c.cache == nil {
  320. return
  321. }
  322. key := dnsCacheKey{Question: question, transportTag: transport.Tag()}
  323. if c.disableExpire {
  324. c.cache.Add(key, message.Copy())
  325. } else {
  326. c.cache.AddWithLifetime(key, message.Copy(), time.Second*time.Duration(timeToLive))
  327. }
  328. }
  329. func (c *Client) lookupToExchange(ctx context.Context, transport adapter.DNSTransport, name string, qType uint16, options adapter.DNSQueryOptions, responseChecker func(response *dns.Msg) bool) ([]netip.Addr, error) {
  330. question := dns.Question{
  331. Name: name,
  332. Qtype: qType,
  333. Qclass: dns.ClassINET,
  334. }
  335. message := dns.Msg{
  336. MsgHdr: dns.MsgHdr{
  337. RecursionDesired: true,
  338. },
  339. Question: []dns.Question{question},
  340. }
  341. disableCache := c.disableCache || options.DisableCache
  342. if !disableCache {
  343. cachedAddresses, err := c.questionCache(ctx, transport, &message, options, responseChecker)
  344. if err != ErrNotCached {
  345. return cachedAddresses, err
  346. }
  347. }
  348. response, err := c.Exchange(ctx, transport, &message, options, responseChecker)
  349. if err != nil {
  350. return nil, err
  351. }
  352. if response.Rcode != dns.RcodeSuccess {
  353. return nil, RcodeError(response.Rcode)
  354. }
  355. return MessageToAddresses(response), nil
  356. }
  357. func (c *Client) questionCache(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg, options adapter.DNSQueryOptions, responseChecker func(response *dns.Msg) bool) ([]netip.Addr, error) {
  358. question := message.Question[0]
  359. response, _, isStale := c.loadResponse(question, transport)
  360. if response == nil {
  361. return nil, ErrNotCached
  362. }
  363. if isStale {
  364. if options.DisableOptimisticCache {
  365. return nil, ErrNotCached
  366. }
  367. c.backgroundRefreshDNS(transport, question, c.prepareExchangeMessage(message.Copy(), options), options, responseChecker)
  368. logOptimisticResponse(c.logger, ctx, response)
  369. }
  370. if response.Rcode != dns.RcodeSuccess {
  371. return nil, RcodeError(response.Rcode)
  372. }
  373. return MessageToAddresses(response), nil
  374. }
  375. func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransport) (*dns.Msg, int, bool) {
  376. if c.dnsCache != nil {
  377. return c.loadPersistentResponse(question, transport)
  378. }
  379. if c.cache == nil {
  380. return nil, 0, false
  381. }
  382. key := dnsCacheKey{Question: question, transportTag: transport.Tag()}
  383. if c.disableExpire {
  384. response, loaded := c.cache.Get(key)
  385. if !loaded {
  386. return nil, 0, false
  387. }
  388. return response.Copy(), 0, false
  389. }
  390. response, expireAt, loaded := c.cache.GetWithLifetimeNoExpire(key)
  391. if !loaded {
  392. return nil, 0, false
  393. }
  394. timeNow := time.Now()
  395. if timeNow.After(expireAt) {
  396. if c.optimisticTimeout > 0 && timeNow.Before(expireAt.Add(c.optimisticTimeout)) {
  397. response = response.Copy()
  398. normalizeTTL(response, 1)
  399. return response, 0, true
  400. }
  401. c.cache.Remove(key)
  402. return nil, 0, false
  403. }
  404. nowTTL := int(expireAt.Sub(timeNow).Seconds())
  405. if nowTTL < 0 {
  406. nowTTL = 0
  407. }
  408. response = response.Copy()
  409. normalizeTTL(response, uint32(nowTTL))
  410. return response, nowTTL, false
  411. }
  412. func (c *Client) loadPersistentResponse(question dns.Question, transport adapter.DNSTransport) (*dns.Msg, int, bool) {
  413. rawMessage, expireAt, loaded := c.dnsCache.LoadDNSCache(transport.Tag(), question.Name, question.Qtype)
  414. if !loaded {
  415. return nil, 0, false
  416. }
  417. response := new(dns.Msg)
  418. err := response.Unpack(rawMessage)
  419. if err != nil {
  420. return nil, 0, false
  421. }
  422. if c.disableExpire {
  423. return response, 0, false
  424. }
  425. timeNow := time.Now()
  426. if timeNow.After(expireAt) {
  427. if c.optimisticTimeout > 0 && timeNow.Before(expireAt.Add(c.optimisticTimeout)) {
  428. normalizeTTL(response, 1)
  429. return response, 0, true
  430. }
  431. return nil, 0, false
  432. }
  433. nowTTL := int(expireAt.Sub(timeNow).Seconds())
  434. if nowTTL < 0 {
  435. nowTTL = 0
  436. }
  437. normalizeTTL(response, uint32(nowTTL))
  438. return response, nowTTL, false
  439. }
  440. func applyResponseOptions(question dns.Question, response *dns.Msg, options adapter.DNSQueryOptions) uint32 {
  441. if question.Qtype == dns.TypeHTTPS && (options.Strategy == C.DomainStrategyIPv4Only || options.Strategy == C.DomainStrategyIPv6Only) {
  442. for _, rr := range response.Answer {
  443. https, isHTTPS := rr.(*dns.HTTPS)
  444. if !isHTTPS {
  445. continue
  446. }
  447. content := https.SVCB
  448. content.Value = common.Filter(content.Value, func(it dns.SVCBKeyValue) bool {
  449. if options.Strategy == C.DomainStrategyIPv4Only {
  450. return it.Key() != dns.SVCB_IPV6HINT
  451. }
  452. return it.Key() != dns.SVCB_IPV4HINT
  453. })
  454. https.SVCB = content
  455. }
  456. }
  457. timeToLive := computeTimeToLive(response)
  458. if options.RewriteTTL != nil {
  459. timeToLive = *options.RewriteTTL
  460. }
  461. normalizeTTL(response, timeToLive)
  462. return timeToLive
  463. }
  464. func (c *Client) backgroundRefreshDNS(transport adapter.DNSTransport, question dns.Question, message *dns.Msg, options adapter.DNSQueryOptions, responseChecker func(response *dns.Msg) bool) {
  465. key := dnsCacheKey{Question: question, transportTag: transport.Tag()}
  466. _, loaded := c.backgroundRefresh.LoadOrStore(key, struct{}{})
  467. if loaded {
  468. return
  469. }
  470. go func() {
  471. defer c.backgroundRefresh.Delete(key)
  472. ctx := contextWithTransportTag(c.ctx, transport.Tag())
  473. response, err := c.exchangeToTransport(ctx, transport, message)
  474. if err != nil {
  475. if c.logger != nil {
  476. c.logger.Debug("optimistic refresh failed for ", FqdnToDomain(question.Name), ": ", err)
  477. }
  478. return
  479. }
  480. if responseChecker != nil {
  481. var rejected bool
  482. if response.Rcode != dns.RcodeSuccess && response.Rcode != dns.RcodeNameError {
  483. rejected = true
  484. } else {
  485. rejected = !responseChecker(response)
  486. }
  487. if rejected {
  488. if c.rdrc != nil {
  489. c.rdrc.SaveRDRCAsync(transport.Tag(), question.Name, question.Qtype, c.logger)
  490. }
  491. return
  492. }
  493. } else if response.Rcode != dns.RcodeSuccess && response.Rcode != dns.RcodeNameError {
  494. return
  495. }
  496. timeToLive := applyResponseOptions(question, response, options)
  497. c.storeCache(transport, question, response, timeToLive)
  498. }()
  499. }
  500. func (c *Client) prepareExchangeMessage(message *dns.Msg, options adapter.DNSQueryOptions) *dns.Msg {
  501. clientSubnet := options.ClientSubnet
  502. if !clientSubnet.IsValid() {
  503. clientSubnet = c.clientSubnet
  504. }
  505. if clientSubnet.IsValid() {
  506. message = SetClientSubnet(message, clientSubnet)
  507. }
  508. return message
  509. }
  510. func stripDNSPadding(response *dns.Msg) {
  511. for _, record := range response.Extra {
  512. opt, isOpt := record.(*dns.OPT)
  513. if !isOpt {
  514. continue
  515. }
  516. opt.Option = common.Filter(opt.Option, func(it dns.EDNS0) bool {
  517. return it.Option() != dns.EDNS0PADDING
  518. })
  519. }
  520. }
  521. func (c *Client) exchangeToTransport(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg) (*dns.Msg, error) {
  522. ctx, cancel := context.WithTimeout(ctx, c.timeout)
  523. defer cancel()
  524. response, err := transport.Exchange(ctx, message)
  525. if err == nil {
  526. stripDNSPadding(response)
  527. return response, nil
  528. }
  529. var rcodeError RcodeError
  530. if errors.As(err, &rcodeError) {
  531. return FixedResponseStatus(message, int(rcodeError)), nil
  532. }
  533. return nil, err
  534. }
  535. func MessageToAddresses(response *dns.Msg) []netip.Addr {
  536. return adapter.DNSResponseAddresses(response)
  537. }
  538. func wrapError(err error) error {
  539. switch dnsErr := err.(type) {
  540. case *net.DNSError:
  541. if dnsErr.IsNotFound {
  542. return RcodeNameError
  543. }
  544. case *net.AddrError:
  545. return RcodeNameError
  546. }
  547. return err
  548. }
  549. type transportKey struct{}
  550. func contextWithTransportTag(ctx context.Context, transportTag string) context.Context {
  551. return context.WithValue(ctx, transportKey{}, transportTag)
  552. }
  553. func transportTagFromContext(ctx context.Context) (string, bool) {
  554. value, loaded := ctx.Value(transportKey{}).(string)
  555. return value, loaded
  556. }
  557. func FixedResponseStatus(message *dns.Msg, rcode int) *dns.Msg {
  558. return &dns.Msg{
  559. MsgHdr: dns.MsgHdr{
  560. Id: message.Id,
  561. Response: true,
  562. Authoritative: true,
  563. RecursionDesired: true,
  564. RecursionAvailable: true,
  565. Rcode: rcode,
  566. },
  567. Question: message.Question,
  568. }
  569. }
  570. func FixedResponse(id uint16, question dns.Question, addresses []netip.Addr, timeToLive uint32) *dns.Msg {
  571. response := dns.Msg{
  572. MsgHdr: dns.MsgHdr{
  573. Id: id,
  574. Response: true,
  575. Authoritative: true,
  576. RecursionDesired: true,
  577. RecursionAvailable: true,
  578. Rcode: dns.RcodeSuccess,
  579. },
  580. Question: []dns.Question{question},
  581. }
  582. for _, address := range addresses {
  583. if address.Is4() && question.Qtype == dns.TypeA {
  584. response.Answer = append(response.Answer, &dns.A{
  585. Hdr: dns.RR_Header{
  586. Name: question.Name,
  587. Rrtype: dns.TypeA,
  588. Class: dns.ClassINET,
  589. Ttl: timeToLive,
  590. },
  591. A: address.AsSlice(),
  592. })
  593. } else if address.Is6() && question.Qtype == dns.TypeAAAA {
  594. response.Answer = append(response.Answer, &dns.AAAA{
  595. Hdr: dns.RR_Header{
  596. Name: question.Name,
  597. Rrtype: dns.TypeAAAA,
  598. Class: dns.ClassINET,
  599. Ttl: timeToLive,
  600. },
  601. AAAA: address.AsSlice(),
  602. })
  603. }
  604. }
  605. return &response
  606. }
  607. func FixedResponseCNAME(id uint16, question dns.Question, record string, timeToLive uint32) *dns.Msg {
  608. response := dns.Msg{
  609. MsgHdr: dns.MsgHdr{
  610. Id: id,
  611. Response: true,
  612. Authoritative: true,
  613. RecursionDesired: true,
  614. RecursionAvailable: true,
  615. Rcode: dns.RcodeSuccess,
  616. },
  617. Question: []dns.Question{question},
  618. Answer: []dns.RR{
  619. &dns.CNAME{
  620. Hdr: dns.RR_Header{
  621. Name: question.Name,
  622. Rrtype: dns.TypeCNAME,
  623. Class: dns.ClassINET,
  624. Ttl: timeToLive,
  625. },
  626. Target: record,
  627. },
  628. },
  629. }
  630. return &response
  631. }
  632. func FixedResponseTXT(id uint16, question dns.Question, records []string, timeToLive uint32) *dns.Msg {
  633. response := dns.Msg{
  634. MsgHdr: dns.MsgHdr{
  635. Id: id,
  636. Response: true,
  637. Authoritative: true,
  638. RecursionDesired: true,
  639. RecursionAvailable: true,
  640. Rcode: dns.RcodeSuccess,
  641. },
  642. Question: []dns.Question{question},
  643. Answer: []dns.RR{
  644. &dns.TXT{
  645. Hdr: dns.RR_Header{
  646. Name: question.Name,
  647. Rrtype: dns.TypeA,
  648. Class: dns.ClassINET,
  649. Ttl: timeToLive,
  650. },
  651. Txt: records,
  652. },
  653. },
  654. }
  655. return &response
  656. }
  657. func FixedResponseMX(id uint16, question dns.Question, records []*net.MX, timeToLive uint32) *dns.Msg {
  658. response := dns.Msg{
  659. MsgHdr: dns.MsgHdr{
  660. Id: id,
  661. Response: true,
  662. Authoritative: true,
  663. RecursionDesired: true,
  664. RecursionAvailable: true,
  665. Rcode: dns.RcodeSuccess,
  666. },
  667. Question: []dns.Question{question},
  668. }
  669. for _, record := range records {
  670. response.Answer = append(response.Answer, &dns.MX{
  671. Hdr: dns.RR_Header{
  672. Name: question.Name,
  673. Rrtype: dns.TypeA,
  674. Class: dns.ClassINET,
  675. Ttl: timeToLive,
  676. },
  677. Preference: record.Pref,
  678. Mx: record.Host,
  679. })
  680. }
  681. return &response
  682. }