dns.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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. err = badjson.UnmarshallExcludedContext(ctx, content, legacyOptions, &o.RawDNSOptions)
  43. if err != nil {
  44. return err
  45. }
  46. rcodeMap := make(map[string]int)
  47. o.Servers = common.Filter(o.Servers, func(it NewDNSServerOptions) bool {
  48. if it.Type == C.DNSTypeLegacyRcode {
  49. rcodeMap[it.Tag] = it.Options.(int)
  50. return false
  51. }
  52. return true
  53. })
  54. if len(rcodeMap) > 0 {
  55. for i := 0; i < len(o.Rules); i++ {
  56. rewriteRcode(rcodeMap, &o.Rules[i])
  57. }
  58. }
  59. return nil
  60. }
  61. func rewriteRcode(rcodeMap map[string]int, rule *DNSRule) {
  62. switch rule.Type {
  63. case C.RuleTypeDefault:
  64. rewriteRcodeAction(rcodeMap, &rule.DefaultOptions.DNSRuleAction)
  65. case C.RuleTypeLogical:
  66. rewriteRcodeAction(rcodeMap, &rule.LogicalOptions.DNSRuleAction)
  67. }
  68. }
  69. func rewriteRcodeAction(rcodeMap map[string]int, ruleAction *DNSRuleAction) {
  70. if ruleAction.Action != C.RuleActionTypeRoute {
  71. return
  72. }
  73. rcode, loaded := rcodeMap[ruleAction.RouteOptions.Server]
  74. if !loaded {
  75. return
  76. }
  77. ruleAction.Action = C.RuleActionTypePredefined
  78. ruleAction.PredefinedOptions.Rcode = common.Ptr(DNSRCode(rcode))
  79. return
  80. }
  81. type DNSClientOptions struct {
  82. Strategy DomainStrategy `json:"strategy,omitempty"`
  83. DisableCache bool `json:"disable_cache,omitempty"`
  84. DisableExpire bool `json:"disable_expire,omitempty"`
  85. IndependentCache bool `json:"independent_cache,omitempty"`
  86. CacheCapacity uint32 `json:"cache_capacity,omitempty"`
  87. ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
  88. }
  89. type LegacyDNSFakeIPOptions struct {
  90. Enabled bool `json:"enabled,omitempty"`
  91. Inet4Range *badoption.Prefix `json:"inet4_range,omitempty"`
  92. Inet6Range *badoption.Prefix `json:"inet6_range,omitempty"`
  93. }
  94. type DNSTransportOptionsRegistry interface {
  95. CreateOptions(transportType string) (any, bool)
  96. }
  97. type _NewDNSServerOptions struct {
  98. Type string `json:"type,omitempty"`
  99. Tag string `json:"tag,omitempty"`
  100. Options any `json:"-"`
  101. }
  102. type NewDNSServerOptions _NewDNSServerOptions
  103. func (o *NewDNSServerOptions) MarshalJSONContext(ctx context.Context) ([]byte, error) {
  104. return badjson.MarshallObjectsContext(ctx, (*_NewDNSServerOptions)(o), o.Options)
  105. }
  106. func (o *NewDNSServerOptions) UnmarshalJSONContext(ctx context.Context, content []byte) error {
  107. err := json.UnmarshalContext(ctx, content, (*_NewDNSServerOptions)(o))
  108. if err != nil {
  109. return err
  110. }
  111. registry := service.FromContext[DNSTransportOptionsRegistry](ctx)
  112. if registry == nil {
  113. return E.New("missing DNS transport options registry in context")
  114. }
  115. var options any
  116. switch o.Type {
  117. case "", C.DNSTypeLegacy:
  118. o.Type = C.DNSTypeLegacy
  119. options = new(LegacyDNSServerOptions)
  120. deprecated.Report(ctx, deprecated.OptionLegacyDNSTransport)
  121. default:
  122. var loaded bool
  123. options, loaded = registry.CreateOptions(o.Type)
  124. if !loaded {
  125. return E.New("unknown transport type: ", o.Type)
  126. }
  127. }
  128. err = badjson.UnmarshallExcludedContext(ctx, content, (*_NewDNSServerOptions)(o), options)
  129. if err != nil {
  130. return err
  131. }
  132. o.Options = options
  133. if o.Type == C.DNSTypeLegacy {
  134. err = o.Upgrade(ctx)
  135. if err != nil {
  136. return err
  137. }
  138. }
  139. return nil
  140. }
  141. func (o *NewDNSServerOptions) Upgrade(ctx context.Context) error {
  142. if o.Type != C.DNSTypeLegacy {
  143. return nil
  144. }
  145. options := o.Options.(*LegacyDNSServerOptions)
  146. serverURL, _ := url.Parse(options.Address)
  147. var serverType string
  148. if serverURL.Scheme != "" {
  149. serverType = serverURL.Scheme
  150. } else {
  151. switch options.Address {
  152. case "local", "fakeip":
  153. serverType = options.Address
  154. default:
  155. serverType = C.DNSTypeUDP
  156. }
  157. }
  158. var remoteOptions RemoteDNSServerOptions
  159. if options.Detour == "" {
  160. remoteOptions = RemoteDNSServerOptions{
  161. LocalDNSServerOptions: LocalDNSServerOptions{
  162. LegacyStrategy: options.Strategy,
  163. LegacyDefaultDialer: options.Detour == "",
  164. LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
  165. },
  166. LegacyAddressResolver: options.AddressResolver,
  167. LegacyAddressStrategy: options.AddressStrategy,
  168. LegacyAddressFallbackDelay: options.AddressFallbackDelay,
  169. }
  170. } else {
  171. remoteOptions = RemoteDNSServerOptions{
  172. LocalDNSServerOptions: LocalDNSServerOptions{
  173. DialerOptions: DialerOptions{
  174. Detour: options.Detour,
  175. DomainResolver: &DomainResolveOptions{
  176. Server: options.AddressResolver,
  177. Strategy: options.AddressStrategy,
  178. },
  179. FallbackDelay: options.AddressFallbackDelay,
  180. },
  181. LegacyStrategy: options.Strategy,
  182. LegacyDefaultDialer: options.Detour == "",
  183. LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
  184. },
  185. }
  186. }
  187. switch serverType {
  188. case C.DNSTypeLocal:
  189. o.Type = C.DNSTypeLocal
  190. o.Options = &remoteOptions.LocalDNSServerOptions
  191. case C.DNSTypeUDP:
  192. o.Type = C.DNSTypeUDP
  193. o.Options = &remoteOptions
  194. var serverAddr M.Socksaddr
  195. if serverURL.Scheme == "" {
  196. serverAddr = M.ParseSocksaddr(options.Address)
  197. } else {
  198. serverAddr = M.ParseSocksaddr(serverURL.Host)
  199. }
  200. if !serverAddr.IsValid() {
  201. return E.New("invalid server address")
  202. }
  203. remoteOptions.Server = serverAddr.AddrString()
  204. if serverAddr.Port != 0 && serverAddr.Port != 53 {
  205. remoteOptions.ServerPort = serverAddr.Port
  206. }
  207. case C.DNSTypeTCP:
  208. o.Type = C.DNSTypeTCP
  209. o.Options = &remoteOptions
  210. serverAddr := M.ParseSocksaddr(serverURL.Host)
  211. if !serverAddr.IsValid() {
  212. return E.New("invalid server address")
  213. }
  214. remoteOptions.Server = serverAddr.AddrString()
  215. if serverAddr.Port != 0 && serverAddr.Port != 53 {
  216. remoteOptions.ServerPort = serverAddr.Port
  217. }
  218. case C.DNSTypeTLS, C.DNSTypeQUIC:
  219. o.Type = serverType
  220. serverAddr := M.ParseSocksaddr(serverURL.Host)
  221. if !serverAddr.IsValid() {
  222. return E.New("invalid server address")
  223. }
  224. remoteOptions.Server = serverAddr.AddrString()
  225. if serverAddr.Port != 0 && serverAddr.Port != 853 {
  226. remoteOptions.ServerPort = serverAddr.Port
  227. }
  228. o.Options = &RemoteTLSDNSServerOptions{
  229. RemoteDNSServerOptions: remoteOptions,
  230. }
  231. case C.DNSTypeHTTPS, C.DNSTypeHTTP3:
  232. o.Type = serverType
  233. httpsOptions := RemoteHTTPSDNSServerOptions{
  234. RemoteTLSDNSServerOptions: RemoteTLSDNSServerOptions{
  235. RemoteDNSServerOptions: remoteOptions,
  236. },
  237. }
  238. o.Options = &httpsOptions
  239. serverAddr := M.ParseSocksaddr(serverURL.Host)
  240. if !serverAddr.IsValid() {
  241. return E.New("invalid server address")
  242. }
  243. httpsOptions.Server = serverAddr.AddrString()
  244. if serverAddr.Port != 0 && serverAddr.Port != 443 {
  245. httpsOptions.ServerPort = serverAddr.Port
  246. }
  247. if serverURL.Path != "/dns-query" {
  248. httpsOptions.Path = serverURL.Path
  249. }
  250. case "rcode":
  251. var rcode int
  252. switch serverURL.Host {
  253. case "success":
  254. rcode = dns.RcodeSuccess
  255. case "format_error":
  256. rcode = dns.RcodeFormatError
  257. case "server_failure":
  258. rcode = dns.RcodeServerFailure
  259. case "name_error":
  260. rcode = dns.RcodeNameError
  261. case "not_implemented":
  262. rcode = dns.RcodeNotImplemented
  263. case "refused":
  264. rcode = dns.RcodeRefused
  265. default:
  266. return E.New("unknown rcode: ", serverURL.Host)
  267. }
  268. o.Type = C.DNSTypeLegacyRcode
  269. o.Options = rcode
  270. case C.DNSTypeDHCP:
  271. o.Type = C.DNSTypeDHCP
  272. dhcpOptions := DHCPDNSServerOptions{}
  273. if serverURL.Host != "" && serverURL.Host != "auto" {
  274. dhcpOptions.Interface = serverURL.Host
  275. }
  276. o.Options = &dhcpOptions
  277. case C.DNSTypeFakeIP:
  278. o.Type = C.DNSTypeFakeIP
  279. fakeipOptions := FakeIPDNSServerOptions{}
  280. if legacyOptions, loaded := ctx.Value((*LegacyDNSFakeIPOptions)(nil)).(*LegacyDNSFakeIPOptions); loaded {
  281. fakeipOptions.Inet4Range = legacyOptions.Inet4Range
  282. fakeipOptions.Inet6Range = legacyOptions.Inet6Range
  283. }
  284. o.Options = &fakeipOptions
  285. default:
  286. return E.New("unsupported DNS server scheme: ", serverType)
  287. }
  288. return nil
  289. }
  290. type LegacyDNSServerOptions struct {
  291. Address string `json:"address"`
  292. AddressResolver string `json:"address_resolver,omitempty"`
  293. AddressStrategy DomainStrategy `json:"address_strategy,omitempty"`
  294. AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"`
  295. Strategy DomainStrategy `json:"strategy,omitempty"`
  296. Detour string `json:"detour,omitempty"`
  297. ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
  298. }
  299. type HostsDNSServerOptions struct {
  300. Path badoption.Listable[string] `json:"path,omitempty"`
  301. Predefined badjson.TypedMap[string, badoption.Listable[netip.Addr]] `json:"predefined,omitempty"`
  302. }
  303. type LocalDNSServerOptions struct {
  304. DialerOptions
  305. LegacyStrategy DomainStrategy `json:"-"`
  306. LegacyDefaultDialer bool `json:"-"`
  307. LegacyClientSubnet netip.Prefix `json:"-"`
  308. }
  309. type RemoteDNSServerOptions struct {
  310. LocalDNSServerOptions
  311. ServerOptions
  312. LegacyAddressResolver string `json:"-"`
  313. LegacyAddressStrategy DomainStrategy `json:"-"`
  314. LegacyAddressFallbackDelay badoption.Duration `json:"-"`
  315. }
  316. type RemoteTLSDNSServerOptions struct {
  317. RemoteDNSServerOptions
  318. OutboundTLSOptionsContainer
  319. }
  320. type RemoteHTTPSDNSServerOptions struct {
  321. RemoteTLSDNSServerOptions
  322. Path string `json:"path,omitempty"`
  323. Method string `json:"method,omitempty"`
  324. Headers badoption.HTTPHeader `json:"headers,omitempty"`
  325. }
  326. type FakeIPDNSServerOptions struct {
  327. Inet4Range *badoption.Prefix `json:"inet4_range,omitempty"`
  328. Inet6Range *badoption.Prefix `json:"inet6_range,omitempty"`
  329. }
  330. type DHCPDNSServerOptions struct {
  331. LocalDNSServerOptions
  332. Interface string `json:"interface,omitempty"`
  333. }