client.go 19 KB

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