dns_record.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package option
  2. import (
  3. "encoding/base64"
  4. "github.com/sagernet/sing/common"
  5. "github.com/sagernet/sing/common/buf"
  6. E "github.com/sagernet/sing/common/exceptions"
  7. "github.com/sagernet/sing/common/json"
  8. "github.com/sagernet/sing/common/json/badoption"
  9. M "github.com/sagernet/sing/common/metadata"
  10. "github.com/miekg/dns"
  11. )
  12. type PredefinedDNSServerOptions struct {
  13. Responses []DNSResponseOptions `json:"responses,omitempty"`
  14. }
  15. type DNSResponseOptions struct {
  16. Query badoption.Listable[string] `json:"query,omitempty"`
  17. QueryType badoption.Listable[DNSQueryType] `json:"query_type,omitempty"`
  18. RCode *DNSRCode `json:"rcode,omitempty"`
  19. Answer badoption.Listable[DNSRecordOptions] `json:"answer,omitempty"`
  20. Ns badoption.Listable[DNSRecordOptions] `json:"ns,omitempty"`
  21. Extra badoption.Listable[DNSRecordOptions] `json:"extra,omitempty"`
  22. }
  23. type DNSRCode int
  24. func (r DNSRCode) MarshalJSON() ([]byte, error) {
  25. rCodeValue, loaded := dns.RcodeToString[int(r)]
  26. if loaded {
  27. return json.Marshal(rCodeValue)
  28. }
  29. return json.Marshal(int(r))
  30. }
  31. func (r *DNSRCode) UnmarshalJSON(bytes []byte) error {
  32. var intValue int
  33. err := json.Unmarshal(bytes, &intValue)
  34. if err == nil {
  35. *r = DNSRCode(intValue)
  36. return nil
  37. }
  38. var stringValue string
  39. err = json.Unmarshal(bytes, &stringValue)
  40. if err != nil {
  41. return err
  42. }
  43. rCodeValue, loaded := dns.StringToRcode[stringValue]
  44. if !loaded {
  45. return E.New("unknown rcode: " + stringValue)
  46. }
  47. *r = DNSRCode(rCodeValue)
  48. return nil
  49. }
  50. func (r *DNSRCode) Build() int {
  51. if r == nil {
  52. return dns.RcodeSuccess
  53. }
  54. return int(*r)
  55. }
  56. func (o DNSResponseOptions) Build() ([]dns.Question, *dns.Msg, error) {
  57. var questions []dns.Question
  58. if len(o.Query) == 0 && len(o.QueryType) == 0 {
  59. questions = []dns.Question{{Qclass: dns.ClassINET}}
  60. } else if len(o.Query) == 0 {
  61. for _, queryType := range o.QueryType {
  62. questions = append(questions, dns.Question{
  63. Qtype: uint16(queryType),
  64. Qclass: dns.ClassINET,
  65. })
  66. }
  67. } else if len(o.QueryType) == 0 {
  68. for _, domain := range o.Query {
  69. questions = append(questions, dns.Question{
  70. Name: dns.Fqdn(domain),
  71. Qclass: dns.ClassINET,
  72. })
  73. }
  74. } else {
  75. for _, queryType := range o.QueryType {
  76. for _, domain := range o.Query {
  77. questions = append(questions, dns.Question{
  78. Name: dns.Fqdn(domain),
  79. Qtype: uint16(queryType),
  80. Qclass: dns.ClassINET,
  81. })
  82. }
  83. }
  84. }
  85. return questions, &dns.Msg{
  86. MsgHdr: dns.MsgHdr{
  87. Response: true,
  88. Rcode: o.RCode.Build(),
  89. Authoritative: true,
  90. RecursionDesired: true,
  91. RecursionAvailable: true,
  92. },
  93. Answer: common.Map(o.Answer, DNSRecordOptions.build),
  94. Ns: common.Map(o.Ns, DNSRecordOptions.build),
  95. Extra: common.Map(o.Extra, DNSRecordOptions.build),
  96. }, nil
  97. }
  98. type DNSRecordOptions struct {
  99. dns.RR
  100. fromBase64 bool
  101. }
  102. func (o DNSRecordOptions) MarshalJSON() ([]byte, error) {
  103. if o.fromBase64 {
  104. buffer := buf.Get(dns.Len(o.RR))
  105. defer buf.Put(buffer)
  106. offset, err := dns.PackRR(o.RR, buffer, 0, nil, false)
  107. if err != nil {
  108. return nil, err
  109. }
  110. return json.Marshal(base64.StdEncoding.EncodeToString(buffer[:offset]))
  111. }
  112. return json.Marshal(o.RR.String())
  113. }
  114. func (o *DNSRecordOptions) UnmarshalJSON(data []byte) error {
  115. var stringValue string
  116. err := json.Unmarshal(data, &stringValue)
  117. if err != nil {
  118. return err
  119. }
  120. binary, err := base64.StdEncoding.DecodeString(stringValue)
  121. if err == nil {
  122. return o.unmarshalBase64(binary)
  123. }
  124. record, err := dns.NewRR(stringValue)
  125. if err != nil {
  126. return err
  127. }
  128. if a, isA := record.(*dns.A); isA {
  129. a.A = M.AddrFromIP(a.A).Unmap().AsSlice()
  130. }
  131. o.RR = record
  132. return nil
  133. }
  134. func (o *DNSRecordOptions) unmarshalBase64(binary []byte) error {
  135. record, _, err := dns.UnpackRR(binary, 0)
  136. if err != nil {
  137. return E.New("parse binary DNS record")
  138. }
  139. o.RR = record
  140. o.fromBase64 = true
  141. return nil
  142. }
  143. func (o DNSRecordOptions) build() dns.RR {
  144. return o.RR
  145. }