dns.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  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 != nil && 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. remoteOptions := RemoteDNSServerOptions{
  175. LocalDNSServerOptions: LocalDNSServerOptions{
  176. DialerOptions: DialerOptions{
  177. Detour: options.Detour,
  178. DomainResolver: &DomainResolveOptions{
  179. Server: options.AddressResolver,
  180. Strategy: options.AddressStrategy,
  181. },
  182. FallbackDelay: options.AddressFallbackDelay,
  183. },
  184. Legacy: true,
  185. LegacyStrategy: options.Strategy,
  186. LegacyDefaultDialer: options.Detour == "",
  187. LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
  188. },
  189. LegacyAddressResolver: options.AddressResolver,
  190. LegacyAddressStrategy: options.AddressStrategy,
  191. LegacyAddressFallbackDelay: options.AddressFallbackDelay,
  192. }
  193. switch serverType {
  194. case C.DNSTypeLocal:
  195. o.Type = C.DNSTypeLocal
  196. o.Options = &remoteOptions.LocalDNSServerOptions
  197. case C.DNSTypeUDP:
  198. o.Type = C.DNSTypeUDP
  199. o.Options = &remoteOptions
  200. var serverAddr M.Socksaddr
  201. if serverURL == nil || serverURL.Scheme == "" {
  202. serverAddr = M.ParseSocksaddr(options.Address)
  203. } else {
  204. serverAddr = M.ParseSocksaddr(serverURL.Host)
  205. }
  206. if !serverAddr.IsValid() {
  207. return E.New("invalid server address")
  208. }
  209. remoteOptions.Server = serverAddr.AddrString()
  210. if serverAddr.Port != 0 && serverAddr.Port != 53 {
  211. remoteOptions.ServerPort = serverAddr.Port
  212. }
  213. case C.DNSTypeTCP:
  214. o.Type = C.DNSTypeTCP
  215. o.Options = &remoteOptions
  216. if serverURL == nil {
  217. return E.New("invalid server address")
  218. }
  219. serverAddr := M.ParseSocksaddr(serverURL.Host)
  220. if !serverAddr.IsValid() {
  221. return E.New("invalid server address")
  222. }
  223. remoteOptions.Server = serverAddr.AddrString()
  224. if serverAddr.Port != 0 && serverAddr.Port != 53 {
  225. remoteOptions.ServerPort = serverAddr.Port
  226. }
  227. case C.DNSTypeTLS, C.DNSTypeQUIC:
  228. o.Type = serverType
  229. if serverURL == nil {
  230. return E.New("invalid server address")
  231. }
  232. serverAddr := M.ParseSocksaddr(serverURL.Host)
  233. if !serverAddr.IsValid() {
  234. return E.New("invalid server address")
  235. }
  236. remoteOptions.Server = serverAddr.AddrString()
  237. if serverAddr.Port != 0 && serverAddr.Port != 853 {
  238. remoteOptions.ServerPort = serverAddr.Port
  239. }
  240. o.Options = &RemoteTLSDNSServerOptions{
  241. RemoteDNSServerOptions: remoteOptions,
  242. }
  243. case C.DNSTypeHTTPS, C.DNSTypeHTTP3:
  244. o.Type = serverType
  245. httpsOptions := RemoteHTTPSDNSServerOptions{
  246. RemoteTLSDNSServerOptions: RemoteTLSDNSServerOptions{
  247. RemoteDNSServerOptions: remoteOptions,
  248. },
  249. }
  250. o.Options = &httpsOptions
  251. if serverURL == nil {
  252. return E.New("invalid server address")
  253. }
  254. serverAddr := M.ParseSocksaddr(serverURL.Host)
  255. if !serverAddr.IsValid() {
  256. return E.New("invalid server address")
  257. }
  258. httpsOptions.Server = serverAddr.AddrString()
  259. if serverAddr.Port != 0 && serverAddr.Port != 443 {
  260. httpsOptions.ServerPort = serverAddr.Port
  261. }
  262. if serverURL.Path != "/dns-query" {
  263. httpsOptions.Path = serverURL.Path
  264. }
  265. case "rcode":
  266. var rcode int
  267. if serverURL == nil {
  268. return E.New("invalid server address")
  269. }
  270. switch serverURL.Host {
  271. case "success":
  272. rcode = dns.RcodeSuccess
  273. case "format_error":
  274. rcode = dns.RcodeFormatError
  275. case "server_failure":
  276. rcode = dns.RcodeServerFailure
  277. case "name_error":
  278. rcode = dns.RcodeNameError
  279. case "not_implemented":
  280. rcode = dns.RcodeNotImplemented
  281. case "refused":
  282. rcode = dns.RcodeRefused
  283. default:
  284. return E.New("unknown rcode: ", serverURL.Host)
  285. }
  286. o.Type = C.DNSTypeLegacyRcode
  287. o.Options = rcode
  288. case C.DNSTypeDHCP:
  289. o.Type = C.DNSTypeDHCP
  290. dhcpOptions := DHCPDNSServerOptions{}
  291. if serverURL == nil {
  292. return E.New("invalid server address")
  293. }
  294. if serverURL.Host != "" && serverURL.Host != "auto" {
  295. dhcpOptions.Interface = serverURL.Host
  296. }
  297. o.Options = &dhcpOptions
  298. case C.DNSTypeFakeIP:
  299. o.Type = C.DNSTypeFakeIP
  300. fakeipOptions := FakeIPDNSServerOptions{}
  301. if legacyOptions, loaded := ctx.Value((*LegacyDNSFakeIPOptions)(nil)).(*LegacyDNSFakeIPOptions); loaded {
  302. fakeipOptions.Inet4Range = legacyOptions.Inet4Range
  303. fakeipOptions.Inet6Range = legacyOptions.Inet6Range
  304. }
  305. o.Options = &fakeipOptions
  306. default:
  307. return E.New("unsupported DNS server scheme: ", serverType)
  308. }
  309. return nil
  310. }
  311. type DNSServerAddressOptions struct {
  312. Server string `json:"server"`
  313. ServerPort uint16 `json:"server_port,omitempty"`
  314. }
  315. func (o DNSServerAddressOptions) Build() M.Socksaddr {
  316. return M.ParseSocksaddrHostPort(o.Server, o.ServerPort)
  317. }
  318. func (o DNSServerAddressOptions) ServerIsDomain() bool {
  319. return M.IsDomainName(o.Server)
  320. }
  321. func (o *DNSServerAddressOptions) TakeServerOptions() ServerOptions {
  322. return ServerOptions(*o)
  323. }
  324. func (o *DNSServerAddressOptions) ReplaceServerOptions(options ServerOptions) {
  325. *o = DNSServerAddressOptions(options)
  326. }
  327. type LegacyDNSServerOptions struct {
  328. Address string `json:"address"`
  329. AddressResolver string `json:"address_resolver,omitempty"`
  330. AddressStrategy DomainStrategy `json:"address_strategy,omitempty"`
  331. AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"`
  332. Strategy DomainStrategy `json:"strategy,omitempty"`
  333. Detour string `json:"detour,omitempty"`
  334. ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
  335. }
  336. type HostsDNSServerOptions struct {
  337. Path badoption.Listable[string] `json:"path,omitempty"`
  338. Predefined *badjson.TypedMap[string, badoption.Listable[netip.Addr]] `json:"predefined,omitempty"`
  339. }
  340. type LocalDNSServerOptions struct {
  341. DialerOptions
  342. Legacy bool `json:"-"`
  343. LegacyStrategy DomainStrategy `json:"-"`
  344. LegacyDefaultDialer bool `json:"-"`
  345. LegacyClientSubnet netip.Prefix `json:"-"`
  346. }
  347. type RemoteDNSServerOptions struct {
  348. LocalDNSServerOptions
  349. DNSServerAddressOptions
  350. LegacyAddressResolver string `json:"-"`
  351. LegacyAddressStrategy DomainStrategy `json:"-"`
  352. LegacyAddressFallbackDelay badoption.Duration `json:"-"`
  353. }
  354. type RemoteTLSDNSServerOptions struct {
  355. RemoteDNSServerOptions
  356. OutboundTLSOptionsContainer
  357. }
  358. type RemoteHTTPSDNSServerOptions struct {
  359. RemoteTLSDNSServerOptions
  360. Path string `json:"path,omitempty"`
  361. Method string `json:"method,omitempty"`
  362. Headers badoption.HTTPHeader `json:"headers,omitempty"`
  363. }
  364. type FakeIPDNSServerOptions struct {
  365. Inet4Range *badoption.Prefix `json:"inet4_range,omitempty"`
  366. Inet6Range *badoption.Prefix `json:"inet6_range,omitempty"`
  367. }
  368. type DHCPDNSServerOptions struct {
  369. LocalDNSServerOptions
  370. Interface string `json:"interface,omitempty"`
  371. }