client.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  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 (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg, options adapter.DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) (*dns.Msg, error) {
  88. if len(message.Question) == 0 {
  89. if c.logger != nil {
  90. c.logger.WarnContext(ctx, "bad question size: ", len(message.Question))
  91. }
  92. return FixedResponseStatus(message, dns.RcodeFormatError), nil
  93. }
  94. question := message.Question[0]
  95. if question.Qtype == dns.TypeA && options.Strategy == C.DomainStrategyIPv6Only || question.Qtype == dns.TypeAAAA && options.Strategy == C.DomainStrategyIPv4Only {
  96. if c.logger != nil {
  97. c.logger.DebugContext(ctx, "strategy rejected")
  98. }
  99. return FixedResponseStatus(message, dns.RcodeSuccess), nil
  100. }
  101. clientSubnet := options.ClientSubnet
  102. if !clientSubnet.IsValid() {
  103. clientSubnet = c.clientSubnet
  104. }
  105. if clientSubnet.IsValid() {
  106. message = SetClientSubnet(message, clientSubnet)
  107. }
  108. isSimpleRequest := len(message.Question) == 1 &&
  109. len(message.Ns) == 0 &&
  110. (len(message.Extra) == 0 || len(message.Extra) == 1 &&
  111. message.Extra[0].Header().Rrtype == dns.TypeOPT &&
  112. message.Extra[0].Header().Class > 0 &&
  113. message.Extra[0].Header().Ttl == 0 &&
  114. len(message.Extra[0].(*dns.OPT).Option) == 0) &&
  115. !options.ClientSubnet.IsValid()
  116. disableCache := !isSimpleRequest || c.disableCache || options.DisableCache
  117. if !disableCache {
  118. if c.cache != nil {
  119. cond, loaded := c.cacheLock.LoadOrStore(question, make(chan struct{}))
  120. if loaded {
  121. <-cond
  122. } else {
  123. defer func() {
  124. c.cacheLock.Delete(question)
  125. close(cond)
  126. }()
  127. }
  128. } else if c.transportCache != nil {
  129. cond, loaded := c.transportCacheLock.LoadOrStore(question, make(chan struct{}))
  130. if loaded {
  131. <-cond
  132. } else {
  133. defer func() {
  134. c.transportCacheLock.Delete(question)
  135. close(cond)
  136. }()
  137. }
  138. }
  139. response, ttl := c.loadResponse(question, transport)
  140. if response != nil {
  141. logCachedResponse(c.logger, ctx, response, ttl)
  142. response.Id = message.Id
  143. return response, nil
  144. }
  145. }
  146. messageId := message.Id
  147. contextTransport, clientSubnetLoaded := transportTagFromContext(ctx)
  148. if clientSubnetLoaded && transport.Tag() == contextTransport {
  149. return nil, E.New("DNS query loopback in transport[", contextTransport, "]")
  150. }
  151. ctx = contextWithTransportTag(ctx, transport.Tag())
  152. if !disableCache && responseChecker != nil && c.rdrc != nil {
  153. rejected := c.rdrc.LoadRDRC(transport.Tag(), question.Name, question.Qtype)
  154. if rejected {
  155. return nil, ErrResponseRejectedCached
  156. }
  157. }
  158. ctx, cancel := context.WithTimeout(ctx, c.timeout)
  159. response, err := transport.Exchange(ctx, message)
  160. cancel()
  161. if err != nil {
  162. var rcodeError RcodeError
  163. if errors.As(err, &rcodeError) {
  164. response = FixedResponseStatus(message, int(rcodeError))
  165. } else {
  166. return nil, err
  167. }
  168. }
  169. /*if question.Qtype == dns.TypeA || question.Qtype == dns.TypeAAAA {
  170. validResponse := response
  171. loop:
  172. for {
  173. var (
  174. addresses int
  175. queryCNAME string
  176. )
  177. for _, rawRR := range validResponse.Answer {
  178. switch rr := rawRR.(type) {
  179. case *dns.A:
  180. break loop
  181. case *dns.AAAA:
  182. break loop
  183. case *dns.CNAME:
  184. queryCNAME = rr.Target
  185. }
  186. }
  187. if queryCNAME == "" {
  188. break
  189. }
  190. exMessage := *message
  191. exMessage.Question = []dns.Question{{
  192. Name: queryCNAME,
  193. Qtype: question.Qtype,
  194. }}
  195. validResponse, err = c.Exchange(ctx, transport, &exMessage, options, responseChecker)
  196. if err != nil {
  197. return nil, err
  198. }
  199. }
  200. if validResponse != response {
  201. response.Answer = append(response.Answer, validResponse.Answer...)
  202. }
  203. }*/
  204. disableCache = disableCache || response.Rcode != dns.RcodeSuccess || len(response.Answer) == 0
  205. if responseChecker != nil {
  206. var rejected bool
  207. // TODO: add accept_any rule and support to check response instead of addresses
  208. if response.Rcode != dns.RcodeSuccess || len(response.Answer) == 0 {
  209. rejected = true
  210. } else {
  211. rejected = !responseChecker(MessageToAddresses(response))
  212. }
  213. if rejected {
  214. if !disableCache && c.rdrc != nil {
  215. c.rdrc.SaveRDRCAsync(transport.Tag(), question.Name, question.Qtype, c.logger)
  216. }
  217. logRejectedResponse(c.logger, ctx, response)
  218. return response, ErrResponseRejected
  219. }
  220. }
  221. if question.Qtype == dns.TypeHTTPS {
  222. if options.Strategy == C.DomainStrategyIPv4Only || options.Strategy == C.DomainStrategyIPv6Only {
  223. for _, rr := range response.Answer {
  224. https, isHTTPS := rr.(*dns.HTTPS)
  225. if !isHTTPS {
  226. continue
  227. }
  228. content := https.SVCB
  229. content.Value = common.Filter(content.Value, func(it dns.SVCBKeyValue) bool {
  230. if options.Strategy == C.DomainStrategyIPv4Only {
  231. return it.Key() != dns.SVCB_IPV6HINT
  232. } else {
  233. return it.Key() != dns.SVCB_IPV4HINT
  234. }
  235. })
  236. https.SVCB = content
  237. }
  238. }
  239. }
  240. var timeToLive uint32
  241. for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
  242. for _, record := range recordList {
  243. if timeToLive == 0 || record.Header().Ttl > 0 && record.Header().Ttl < timeToLive {
  244. timeToLive = record.Header().Ttl
  245. }
  246. }
  247. }
  248. if options.RewriteTTL != nil {
  249. timeToLive = *options.RewriteTTL
  250. }
  251. for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
  252. for _, record := range recordList {
  253. record.Header().Ttl = timeToLive
  254. }
  255. }
  256. if !disableCache {
  257. c.storeCache(transport, question, response, timeToLive)
  258. }
  259. response.Id = messageId
  260. requestEDNSOpt := message.IsEdns0()
  261. responseEDNSOpt := response.IsEdns0()
  262. if responseEDNSOpt != nil && (requestEDNSOpt == nil || requestEDNSOpt.Version() < responseEDNSOpt.Version()) {
  263. response.Extra = common.Filter(response.Extra, func(it dns.RR) bool {
  264. return it.Header().Rrtype != dns.TypeOPT
  265. })
  266. if requestEDNSOpt != nil {
  267. response.SetEdns0(responseEDNSOpt.UDPSize(), responseEDNSOpt.Do())
  268. }
  269. }
  270. logExchangedResponse(c.logger, ctx, response, timeToLive)
  271. return response, nil
  272. }
  273. func (c *Client) Lookup(ctx context.Context, transport adapter.DNSTransport, domain string, options adapter.DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) ([]netip.Addr, error) {
  274. domain = FqdnToDomain(domain)
  275. dnsName := dns.Fqdn(domain)
  276. var strategy C.DomainStrategy
  277. if options.LookupStrategy != C.DomainStrategyAsIS {
  278. strategy = options.LookupStrategy
  279. } else {
  280. strategy = options.Strategy
  281. }
  282. if strategy == C.DomainStrategyIPv4Only {
  283. return c.lookupToExchange(ctx, transport, dnsName, dns.TypeA, options, responseChecker)
  284. } else if strategy == C.DomainStrategyIPv6Only {
  285. return c.lookupToExchange(ctx, transport, dnsName, dns.TypeAAAA, options, responseChecker)
  286. }
  287. var response4 []netip.Addr
  288. var response6 []netip.Addr
  289. var group task.Group
  290. group.Append("exchange4", func(ctx context.Context) error {
  291. response, err := c.lookupToExchange(ctx, transport, dnsName, dns.TypeA, options, responseChecker)
  292. if err != nil {
  293. return err
  294. }
  295. response4 = response
  296. return nil
  297. })
  298. group.Append("exchange6", func(ctx context.Context) error {
  299. response, err := c.lookupToExchange(ctx, transport, dnsName, dns.TypeAAAA, options, responseChecker)
  300. if err != nil {
  301. return err
  302. }
  303. response6 = response
  304. return nil
  305. })
  306. err := group.Run(ctx)
  307. if len(response4) == 0 && len(response6) == 0 {
  308. return nil, err
  309. }
  310. return sortAddresses(response4, response6, strategy), nil
  311. }
  312. func (c *Client) ClearCache() {
  313. if c.cache != nil {
  314. c.cache.Purge()
  315. } else if c.transportCache != nil {
  316. c.transportCache.Purge()
  317. }
  318. }
  319. func (c *Client) LookupCache(domain string, strategy C.DomainStrategy) ([]netip.Addr, bool) {
  320. if c.disableCache || c.independentCache {
  321. return nil, false
  322. }
  323. if dns.IsFqdn(domain) {
  324. domain = domain[:len(domain)-1]
  325. }
  326. dnsName := dns.Fqdn(domain)
  327. if strategy == C.DomainStrategyIPv4Only {
  328. addresses, err := c.questionCache(dns.Question{
  329. Name: dnsName,
  330. Qtype: dns.TypeA,
  331. Qclass: dns.ClassINET,
  332. }, nil)
  333. if err != ErrNotCached {
  334. return addresses, true
  335. }
  336. } else if strategy == C.DomainStrategyIPv6Only {
  337. addresses, err := c.questionCache(dns.Question{
  338. Name: dnsName,
  339. Qtype: dns.TypeAAAA,
  340. Qclass: dns.ClassINET,
  341. }, nil)
  342. if err != ErrNotCached {
  343. return addresses, true
  344. }
  345. } else {
  346. response4, _ := c.loadResponse(dns.Question{
  347. Name: dnsName,
  348. Qtype: dns.TypeA,
  349. Qclass: dns.ClassINET,
  350. }, nil)
  351. response6, _ := c.loadResponse(dns.Question{
  352. Name: dnsName,
  353. Qtype: dns.TypeAAAA,
  354. Qclass: dns.ClassINET,
  355. }, nil)
  356. if response4 != nil || response6 != nil {
  357. return sortAddresses(MessageToAddresses(response4), MessageToAddresses(response6), strategy), true
  358. }
  359. }
  360. return nil, false
  361. }
  362. func (c *Client) ExchangeCache(ctx context.Context, message *dns.Msg) (*dns.Msg, bool) {
  363. if c.disableCache || c.independentCache || len(message.Question) != 1 {
  364. return nil, false
  365. }
  366. question := message.Question[0]
  367. response, ttl := c.loadResponse(question, nil)
  368. if response == nil {
  369. return nil, false
  370. }
  371. logCachedResponse(c.logger, ctx, response, ttl)
  372. response.Id = message.Id
  373. return response, true
  374. }
  375. func sortAddresses(response4 []netip.Addr, response6 []netip.Addr, strategy C.DomainStrategy) []netip.Addr {
  376. if strategy == C.DomainStrategyPreferIPv6 {
  377. return append(response6, response4...)
  378. } else {
  379. return append(response4, response6...)
  380. }
  381. }
  382. func (c *Client) storeCache(transport adapter.DNSTransport, question dns.Question, message *dns.Msg, timeToLive uint32) {
  383. if timeToLive == 0 {
  384. return
  385. }
  386. if c.disableExpire {
  387. if !c.independentCache {
  388. c.cache.Add(question, message)
  389. } else {
  390. c.transportCache.Add(transportCacheKey{
  391. Question: question,
  392. transportTag: transport.Tag(),
  393. }, message)
  394. }
  395. } else {
  396. if !c.independentCache {
  397. c.cache.AddWithLifetime(question, message, time.Second*time.Duration(timeToLive))
  398. } else {
  399. c.transportCache.AddWithLifetime(transportCacheKey{
  400. Question: question,
  401. transportTag: transport.Tag(),
  402. }, message, time.Second*time.Duration(timeToLive))
  403. }
  404. }
  405. }
  406. 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) {
  407. question := dns.Question{
  408. Name: name,
  409. Qtype: qType,
  410. Qclass: dns.ClassINET,
  411. }
  412. disableCache := c.disableCache || options.DisableCache
  413. if !disableCache {
  414. cachedAddresses, err := c.questionCache(question, transport)
  415. if err != ErrNotCached {
  416. return cachedAddresses, err
  417. }
  418. }
  419. message := dns.Msg{
  420. MsgHdr: dns.MsgHdr{
  421. RecursionDesired: true,
  422. },
  423. Question: []dns.Question{question},
  424. }
  425. response, err := c.Exchange(ctx, transport, &message, options, responseChecker)
  426. if err != nil {
  427. return nil, err
  428. }
  429. if response.Rcode != dns.RcodeSuccess {
  430. return nil, RcodeError(response.Rcode)
  431. }
  432. return MessageToAddresses(response), nil
  433. }
  434. func (c *Client) questionCache(question dns.Question, transport adapter.DNSTransport) ([]netip.Addr, error) {
  435. response, _ := c.loadResponse(question, transport)
  436. if response == nil {
  437. return nil, ErrNotCached
  438. }
  439. if response.Rcode != dns.RcodeSuccess {
  440. return nil, RcodeError(response.Rcode)
  441. }
  442. return MessageToAddresses(response), nil
  443. }
  444. func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransport) (*dns.Msg, int) {
  445. var (
  446. response *dns.Msg
  447. loaded bool
  448. )
  449. if c.disableExpire {
  450. if !c.independentCache {
  451. response, loaded = c.cache.Get(question)
  452. } else {
  453. response, loaded = c.transportCache.Get(transportCacheKey{
  454. Question: question,
  455. transportTag: transport.Tag(),
  456. })
  457. }
  458. if !loaded {
  459. return nil, 0
  460. }
  461. return response.Copy(), 0
  462. } else {
  463. var expireAt time.Time
  464. if !c.independentCache {
  465. response, expireAt, loaded = c.cache.GetWithLifetime(question)
  466. } else {
  467. response, expireAt, loaded = c.transportCache.GetWithLifetime(transportCacheKey{
  468. Question: question,
  469. transportTag: transport.Tag(),
  470. })
  471. }
  472. if !loaded {
  473. return nil, 0
  474. }
  475. timeNow := time.Now()
  476. if timeNow.After(expireAt) {
  477. if !c.independentCache {
  478. c.cache.Remove(question)
  479. } else {
  480. c.transportCache.Remove(transportCacheKey{
  481. Question: question,
  482. transportTag: transport.Tag(),
  483. })
  484. }
  485. return nil, 0
  486. }
  487. var originTTL int
  488. for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
  489. for _, record := range recordList {
  490. if originTTL == 0 || record.Header().Ttl > 0 && int(record.Header().Ttl) < originTTL {
  491. originTTL = int(record.Header().Ttl)
  492. }
  493. }
  494. }
  495. nowTTL := int(expireAt.Sub(timeNow).Seconds())
  496. if nowTTL < 0 {
  497. nowTTL = 0
  498. }
  499. response = response.Copy()
  500. if originTTL > 0 {
  501. duration := uint32(originTTL - nowTTL)
  502. for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
  503. for _, record := range recordList {
  504. record.Header().Ttl = record.Header().Ttl - duration
  505. }
  506. }
  507. } else {
  508. for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
  509. for _, record := range recordList {
  510. record.Header().Ttl = uint32(nowTTL)
  511. }
  512. }
  513. }
  514. return response, nowTTL
  515. }
  516. }
  517. func MessageToAddresses(response *dns.Msg) []netip.Addr {
  518. if response == nil || response.Rcode != dns.RcodeSuccess {
  519. return nil
  520. }
  521. addresses := make([]netip.Addr, 0, len(response.Answer))
  522. for _, rawAnswer := range response.Answer {
  523. switch answer := rawAnswer.(type) {
  524. case *dns.A:
  525. addresses = append(addresses, M.AddrFromIP(answer.A))
  526. case *dns.AAAA:
  527. addresses = append(addresses, M.AddrFromIP(answer.AAAA))
  528. case *dns.HTTPS:
  529. for _, value := range answer.SVCB.Value {
  530. if value.Key() == dns.SVCB_IPV4HINT || value.Key() == dns.SVCB_IPV6HINT {
  531. addresses = append(addresses, common.Map(strings.Split(value.String(), ","), M.ParseAddr)...)
  532. }
  533. }
  534. }
  535. }
  536. return addresses
  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. }