1
0

dns.go 12 KB

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