dns_record.go 3.7 KB

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