dns.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. package option
  2. import (
  3. "context"
  4. "net/netip"
  5. "net/url"
  6. C "github.com/sagernet/sing-box/constant"
  7. "github.com/sagernet/sing-box/experimental/deprecated"
  8. "github.com/sagernet/sing/common"
  9. E "github.com/sagernet/sing/common/exceptions"
  10. "github.com/sagernet/sing/common/json"
  11. "github.com/sagernet/sing/common/json/badjson"
  12. "github.com/sagernet/sing/common/json/badoption"
  13. M "github.com/sagernet/sing/common/metadata"
  14. "github.com/sagernet/sing/service"
  15. "github.com/miekg/dns"
  16. )
  17. type RawDNSOptions struct {
  18. Servers []NewDNSServerOptions `json:"servers,omitempty"`
  19. Rules []DNSRule `json:"rules,omitempty"`
  20. Final string `json:"final,omitempty"`
  21. ReverseMapping bool `json:"reverse_mapping,omitempty"`
  22. DNSClientOptions
  23. }
  24. type LegacyDNSOptions struct {
  25. FakeIP *LegacyDNSFakeIPOptions `json:"fakeip,omitempty"`
  26. }
  27. type DNSOptions struct {
  28. RawDNSOptions
  29. LegacyDNSOptions
  30. }
  31. func (o *DNSOptions) UnmarshalJSONContext(ctx context.Context, content []byte) error {
  32. err := json.UnmarshalContext(ctx, content, &o.LegacyDNSOptions)
  33. if err != nil {
  34. return err
  35. }
  36. if o.FakeIP != nil && o.FakeIP.Enabled {
  37. deprecated.Report(ctx, deprecated.OptionLegacyDNSFakeIPOptions)
  38. ctx = context.WithValue(ctx, (*LegacyDNSFakeIPOptions)(nil), o.FakeIP)
  39. }
  40. legacyOptions := o.LegacyDNSOptions
  41. o.LegacyDNSOptions = LegacyDNSOptions{}
  42. return badjson.UnmarshallExcludedContext(ctx, content, legacyOptions, &o.RawDNSOptions)
  43. }
  44. type DNSClientOptions struct {
  45. Strategy DomainStrategy `json:"strategy,omitempty"`
  46. DisableCache bool `json:"disable_cache,omitempty"`
  47. DisableExpire bool `json:"disable_expire,omitempty"`
  48. IndependentCache bool `json:"independent_cache,omitempty"`
  49. CacheCapacity uint32 `json:"cache_capacity,omitempty"`
  50. ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
  51. }
  52. type LegacyDNSFakeIPOptions struct {
  53. Enabled bool `json:"enabled,omitempty"`
  54. Inet4Range *badoption.Prefix `json:"inet4_range,omitempty"`
  55. Inet6Range *badoption.Prefix `json:"inet6_range,omitempty"`
  56. }
  57. type DNSTransportOptionsRegistry interface {
  58. CreateOptions(transportType string) (any, bool)
  59. }
  60. type _NewDNSServerOptions struct {
  61. Type string `json:"type,omitempty"`
  62. Tag string `json:"tag,omitempty"`
  63. Options any `json:"-"`
  64. }
  65. type NewDNSServerOptions _NewDNSServerOptions
  66. func (o *NewDNSServerOptions) MarshalJSONContext(ctx context.Context) ([]byte, error) {
  67. return badjson.MarshallObjectsContext(ctx, (*_NewDNSServerOptions)(o), o.Options)
  68. }
  69. func (o *NewDNSServerOptions) UnmarshalJSONContext(ctx context.Context, content []byte) error {
  70. err := json.UnmarshalContext(ctx, content, (*_NewDNSServerOptions)(o))
  71. if err != nil {
  72. return err
  73. }
  74. registry := service.FromContext[DNSTransportOptionsRegistry](ctx)
  75. if registry == nil {
  76. return E.New("missing outbound options registry in context")
  77. }
  78. var options any
  79. switch o.Type {
  80. case "", C.DNSTypeLegacy:
  81. o.Type = C.DNSTypeLegacy
  82. options = new(LegacyDNSServerOptions)
  83. deprecated.Report(ctx, deprecated.OptionLegacyDNSTransport)
  84. default:
  85. var loaded bool
  86. options, loaded = registry.CreateOptions(o.Type)
  87. if !loaded {
  88. return E.New("unknown transport type: ", o.Type)
  89. }
  90. }
  91. err = badjson.UnmarshallExcludedContext(ctx, content, (*_Outbound)(o), options)
  92. if err != nil {
  93. return err
  94. }
  95. o.Options = options
  96. if o.Type == C.DNSTypeLegacy {
  97. err = o.Upgrade(ctx)
  98. if err != nil {
  99. return err
  100. }
  101. }
  102. return nil
  103. }
  104. func (o *NewDNSServerOptions) Upgrade(ctx context.Context) error {
  105. if o.Type != C.DNSTypeLegacy {
  106. return nil
  107. }
  108. options := o.Options.(*LegacyDNSServerOptions)
  109. serverURL, _ := url.Parse(options.Address)
  110. var serverType string
  111. if serverURL.Scheme != "" {
  112. serverType = serverURL.Scheme
  113. } else {
  114. serverType = C.DNSTypeUDP
  115. }
  116. remoteOptions := RemoteDNSServerOptions{
  117. LocalDNSServerOptions: LocalDNSServerOptions{
  118. DialerOptions: DialerOptions{
  119. Detour: options.Detour,
  120. },
  121. LegacyStrategy: options.Strategy,
  122. LegacyDefaultDialer: options.Detour == "",
  123. LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
  124. },
  125. AddressResolver: options.AddressResolver,
  126. AddressStrategy: options.AddressStrategy,
  127. AddressFallbackDelay: options.AddressFallbackDelay,
  128. }
  129. switch serverType {
  130. case C.DNSTypeUDP:
  131. o.Type = C.DNSTypeUDP
  132. o.Options = &remoteOptions
  133. var serverAddr M.Socksaddr
  134. if serverURL.Scheme == "" {
  135. serverAddr = M.ParseSocksaddr(options.Address)
  136. } else {
  137. serverAddr = M.ParseSocksaddr(serverURL.Host)
  138. }
  139. if !serverAddr.IsValid() {
  140. return E.New("invalid server address")
  141. }
  142. remoteOptions.Server = serverAddr.Addr.String()
  143. if serverAddr.Port != 0 && serverAddr.Port != 53 {
  144. remoteOptions.ServerPort = serverAddr.Port
  145. }
  146. case C.DNSTypeTCP:
  147. o.Type = C.DNSTypeTCP
  148. o.Options = &remoteOptions
  149. serverAddr := M.ParseSocksaddr(serverURL.Host)
  150. if !serverAddr.IsValid() {
  151. return E.New("invalid server address")
  152. }
  153. remoteOptions.Server = serverAddr.Addr.String()
  154. if serverAddr.Port != 0 && serverAddr.Port != 53 {
  155. remoteOptions.ServerPort = serverAddr.Port
  156. }
  157. case C.DNSTypeTLS, C.DNSTypeQUIC:
  158. o.Type = serverType
  159. tlsOptions := RemoteTLSDNSServerOptions{
  160. RemoteDNSServerOptions: remoteOptions,
  161. }
  162. o.Options = &tlsOptions
  163. serverAddr := M.ParseSocksaddr(serverURL.Host)
  164. if !serverAddr.IsValid() {
  165. return E.New("invalid server address")
  166. }
  167. tlsOptions.Server = serverAddr.Addr.String()
  168. if serverAddr.Port != 0 && serverAddr.Port != 853 {
  169. tlsOptions.ServerPort = serverAddr.Port
  170. }
  171. case C.DNSTypeHTTPS, C.DNSTypeHTTP3:
  172. o.Type = serverType
  173. httpsOptions := RemoteHTTPSDNSServerOptions{
  174. RemoteTLSDNSServerOptions: RemoteTLSDNSServerOptions{
  175. RemoteDNSServerOptions: remoteOptions,
  176. },
  177. }
  178. o.Options = &httpsOptions
  179. serverAddr := M.ParseSocksaddr(serverURL.Host)
  180. if !serverAddr.IsValid() {
  181. return E.New("invalid server address")
  182. }
  183. httpsOptions.Server = serverAddr.Addr.String()
  184. if serverAddr.Port != 0 && serverAddr.Port != 443 {
  185. httpsOptions.ServerPort = serverAddr.Port
  186. }
  187. if serverURL.Path != "/dns-query" {
  188. httpsOptions.Path = serverURL.Path
  189. }
  190. case "rcode":
  191. var rcode int
  192. switch serverURL.Host {
  193. case "success":
  194. rcode = dns.RcodeSuccess
  195. case "format_error":
  196. rcode = dns.RcodeFormatError
  197. case "server_failure":
  198. rcode = dns.RcodeServerFailure
  199. case "name_error":
  200. rcode = dns.RcodeNameError
  201. case "not_implemented":
  202. rcode = dns.RcodeNotImplemented
  203. case "refused":
  204. rcode = dns.RcodeRefused
  205. default:
  206. return E.New("unknown rcode: ", serverURL.Host)
  207. }
  208. o.Type = C.DNSTypePreDefined
  209. o.Options = &PredefinedDNSServerOptions{
  210. Responses: []DNSResponseOptions{
  211. {
  212. RCode: common.Ptr(DNSRCode(rcode)),
  213. },
  214. },
  215. }
  216. case "dhcp":
  217. o.Type = C.DNSTypeDHCP
  218. dhcpOptions := DHCPDNSServerOptions{}
  219. if serverURL.Host != "" && serverURL.Host != "auto" {
  220. dhcpOptions.Interface = serverURL.Host
  221. }
  222. o.Options = &dhcpOptions
  223. case "fakeip":
  224. o.Type = C.DNSTypeFakeIP
  225. fakeipOptions := FakeIPDNSServerOptions{}
  226. if legacyOptions, loaded := ctx.Value((*LegacyDNSFakeIPOptions)(nil)).(*LegacyDNSFakeIPOptions); loaded {
  227. fakeipOptions.Inet4Range = legacyOptions.Inet4Range
  228. fakeipOptions.Inet6Range = legacyOptions.Inet6Range
  229. }
  230. o.Options = &fakeipOptions
  231. default:
  232. return E.New("unsupported DNS server scheme: ", serverType)
  233. }
  234. return nil
  235. }
  236. type LegacyDNSServerOptions struct {
  237. Address string `json:"address"`
  238. AddressResolver string `json:"address_resolver,omitempty"`
  239. AddressStrategy DomainStrategy `json:"address_strategy,omitempty"`
  240. AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"`
  241. Strategy DomainStrategy `json:"strategy,omitempty"`
  242. Detour string `json:"detour,omitempty"`
  243. ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
  244. }
  245. type HostsDNSServerOptions struct {
  246. Path badoption.Listable[string] `json:"path,omitempty"`
  247. Predefined badjson.TypedMap[string, badoption.Listable[netip.Addr]] `json:"predefined,omitempty"`
  248. }
  249. type LocalDNSServerOptions struct {
  250. DialerOptions
  251. LegacyStrategy DomainStrategy `json:"-"`
  252. LegacyDefaultDialer bool `json:"-"`
  253. LegacyClientSubnet netip.Prefix `json:"-"`
  254. }
  255. type RemoteDNSServerOptions struct {
  256. LocalDNSServerOptions
  257. ServerOptions
  258. AddressResolver string `json:"address_resolver,omitempty"`
  259. AddressStrategy DomainStrategy `json:"address_strategy,omitempty"`
  260. AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"`
  261. }
  262. type RemoteTLSDNSServerOptions struct {
  263. RemoteDNSServerOptions
  264. OutboundTLSOptionsContainer
  265. }
  266. type RemoteHTTPSDNSServerOptions struct {
  267. RemoteTLSDNSServerOptions
  268. Path string `json:"path,omitempty"`
  269. Method string `json:"method,omitempty"`
  270. Headers badoption.HTTPHeader `json:"headers,omitempty"`
  271. }
  272. type FakeIPDNSServerOptions struct {
  273. Inet4Range *badoption.Prefix `json:"inet4_range,omitempty"`
  274. Inet6Range *badoption.Prefix `json:"inet6_range,omitempty"`
  275. }
  276. type DHCPDNSServerOptions struct {
  277. LocalDNSServerOptions
  278. Interface string `json:"interface,omitempty"`
  279. }