client.go 20 KB

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