dns.go 11 KB

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