dns.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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. }
  92. type DNSClientOptions struct {
  93. Strategy DomainStrategy `json:"strategy,omitempty"`
  94. DisableCache bool `json:"disable_cache,omitempty"`
  95. DisableExpire bool `json:"disable_expire,omitempty"`
  96. IndependentCache bool `json:"independent_cache,omitempty"`
  97. CacheCapacity uint32 `json:"cache_capacity,omitempty"`
  98. ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
  99. }
  100. type LegacyDNSFakeIPOptions struct {
  101. Enabled bool `json:"enabled,omitempty"`
  102. Inet4Range *badoption.Prefix `json:"inet4_range,omitempty"`
  103. Inet6Range *badoption.Prefix `json:"inet6_range,omitempty"`
  104. }
  105. type DNSTransportOptionsRegistry interface {
  106. CreateOptions(transportType string) (any, bool)
  107. }
  108. type _DNSServerOptions struct {
  109. Type string `json:"type,omitempty"`
  110. Tag string `json:"tag,omitempty"`
  111. Options any `json:"-"`
  112. }
  113. type DNSServerOptions _DNSServerOptions
  114. func (o *DNSServerOptions) MarshalJSONContext(ctx context.Context) ([]byte, error) {
  115. switch o.Type {
  116. case C.DNSTypeLegacy:
  117. o.Type = ""
  118. }
  119. return badjson.MarshallObjectsContext(ctx, (*_DNSServerOptions)(o), o.Options)
  120. }
  121. func (o *DNSServerOptions) UnmarshalJSONContext(ctx context.Context, content []byte) error {
  122. err := json.UnmarshalContext(ctx, content, (*_DNSServerOptions)(o))
  123. if err != nil {
  124. return err
  125. }
  126. registry := service.FromContext[DNSTransportOptionsRegistry](ctx)
  127. if registry == nil {
  128. return E.New("missing DNS transport options registry in context")
  129. }
  130. var options any
  131. switch o.Type {
  132. case "", C.DNSTypeLegacy:
  133. o.Type = C.DNSTypeLegacy
  134. options = new(LegacyDNSServerOptions)
  135. deprecated.Report(ctx, deprecated.OptionLegacyDNSTransport)
  136. default:
  137. var loaded bool
  138. options, loaded = registry.CreateOptions(o.Type)
  139. if !loaded {
  140. return E.New("unknown transport type: ", o.Type)
  141. }
  142. }
  143. err = badjson.UnmarshallExcludedContext(ctx, content, (*_DNSServerOptions)(o), options)
  144. if err != nil {
  145. return err
  146. }
  147. o.Options = options
  148. if o.Type == C.DNSTypeLegacy && !dontUpgradeFromContext(ctx) {
  149. err = o.Upgrade(ctx)
  150. if err != nil {
  151. return err
  152. }
  153. }
  154. return nil
  155. }
  156. func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
  157. if o.Type != C.DNSTypeLegacy {
  158. return nil
  159. }
  160. options := o.Options.(*LegacyDNSServerOptions)
  161. serverURL, _ := url.Parse(options.Address)
  162. var serverType string
  163. if serverURL != nil && serverURL.Scheme != "" {
  164. serverType = serverURL.Scheme
  165. } else {
  166. switch options.Address {
  167. case "local", "fakeip":
  168. serverType = options.Address
  169. default:
  170. serverType = C.DNSTypeUDP
  171. }
  172. }
  173. remoteOptions := RemoteDNSServerOptions{
  174. RawLocalDNSServerOptions: RawLocalDNSServerOptions{
  175. DialerOptions: DialerOptions{
  176. Detour: options.Detour,
  177. DomainResolver: &DomainResolveOptions{
  178. Server: options.AddressResolver,
  179. Strategy: options.AddressStrategy,
  180. },
  181. FallbackDelay: options.AddressFallbackDelay,
  182. },
  183. Legacy: true,
  184. LegacyStrategy: options.Strategy,
  185. LegacyDefaultDialer: options.Detour == "",
  186. LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
  187. },
  188. LegacyAddressResolver: options.AddressResolver,
  189. LegacyAddressStrategy: options.AddressStrategy,
  190. LegacyAddressFallbackDelay: options.AddressFallbackDelay,
  191. }
  192. switch serverType {
  193. case C.DNSTypeLocal:
  194. o.Type = C.DNSTypeLocal
  195. o.Options = &LocalDNSServerOptions{
  196. RawLocalDNSServerOptions: remoteOptions.RawLocalDNSServerOptions,
  197. }
  198. case C.DNSTypeUDP:
  199. o.Type = C.DNSTypeUDP
  200. o.Options = &remoteOptions
  201. var serverAddr M.Socksaddr
  202. if serverURL == nil || serverURL.Scheme == "" {
  203. serverAddr = M.ParseSocksaddr(options.Address)
  204. } else {
  205. serverAddr = M.ParseSocksaddr(serverURL.Host)
  206. }
  207. if !serverAddr.IsValid() {
  208. return E.New("invalid server address")
  209. }
  210. remoteOptions.Server = serverAddr.AddrString()
  211. if serverAddr.Port != 0 && serverAddr.Port != 53 {
  212. remoteOptions.ServerPort = serverAddr.Port
  213. }
  214. case C.DNSTypeTCP:
  215. o.Type = C.DNSTypeTCP
  216. o.Options = &remoteOptions
  217. if serverURL == nil {
  218. return E.New("invalid server address")
  219. }
  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 != 53 {
  226. remoteOptions.ServerPort = serverAddr.Port
  227. }
  228. case C.DNSTypeTLS, C.DNSTypeQUIC:
  229. o.Type = serverType
  230. if serverURL == nil {
  231. return E.New("invalid server address")
  232. }
  233. serverAddr := M.ParseSocksaddr(serverURL.Host)
  234. if !serverAddr.IsValid() {
  235. return E.New("invalid server address")
  236. }
  237. remoteOptions.Server = serverAddr.AddrString()
  238. if serverAddr.Port != 0 && serverAddr.Port != 853 {
  239. remoteOptions.ServerPort = serverAddr.Port
  240. }
  241. o.Options = &RemoteTLSDNSServerOptions{
  242. RemoteDNSServerOptions: remoteOptions,
  243. }
  244. case C.DNSTypeHTTPS, C.DNSTypeHTTP3:
  245. o.Type = serverType
  246. httpsOptions := RemoteHTTPSDNSServerOptions{
  247. RemoteTLSDNSServerOptions: RemoteTLSDNSServerOptions{
  248. RemoteDNSServerOptions: remoteOptions,
  249. },
  250. }
  251. o.Options = &httpsOptions
  252. if serverURL == nil {
  253. return E.New("invalid server address")
  254. }
  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. if serverURL == nil {
  269. return E.New("invalid server address")
  270. }
  271. switch serverURL.Host {
  272. case "success":
  273. rcode = dns.RcodeSuccess
  274. case "format_error":
  275. rcode = dns.RcodeFormatError
  276. case "server_failure":
  277. rcode = dns.RcodeServerFailure
  278. case "name_error":
  279. rcode = dns.RcodeNameError
  280. case "not_implemented":
  281. rcode = dns.RcodeNotImplemented
  282. case "refused":
  283. rcode = dns.RcodeRefused
  284. default:
  285. return E.New("unknown rcode: ", serverURL.Host)
  286. }
  287. o.Type = C.DNSTypeLegacyRcode
  288. o.Options = rcode
  289. case C.DNSTypeDHCP:
  290. o.Type = C.DNSTypeDHCP
  291. dhcpOptions := DHCPDNSServerOptions{}
  292. if serverURL == nil {
  293. return E.New("invalid server address")
  294. }
  295. if serverURL.Host != "" && serverURL.Host != "auto" {
  296. dhcpOptions.Interface = serverURL.Host
  297. }
  298. o.Options = &dhcpOptions
  299. case C.DNSTypeFakeIP:
  300. o.Type = C.DNSTypeFakeIP
  301. fakeipOptions := FakeIPDNSServerOptions{}
  302. if legacyOptions, loaded := ctx.Value((*LegacyDNSFakeIPOptions)(nil)).(*LegacyDNSFakeIPOptions); loaded {
  303. fakeipOptions.Inet4Range = legacyOptions.Inet4Range
  304. fakeipOptions.Inet6Range = legacyOptions.Inet6Range
  305. }
  306. o.Options = &fakeipOptions
  307. default:
  308. return E.New("unsupported DNS server scheme: ", serverType)
  309. }
  310. return nil
  311. }
  312. type DNSServerAddressOptions struct {
  313. Server string `json:"server"`
  314. ServerPort uint16 `json:"server_port,omitempty"`
  315. }
  316. func (o DNSServerAddressOptions) Build() M.Socksaddr {
  317. return M.ParseSocksaddrHostPort(o.Server, o.ServerPort)
  318. }
  319. func (o DNSServerAddressOptions) ServerIsDomain() bool {
  320. return M.IsDomainName(o.Server)
  321. }
  322. func (o *DNSServerAddressOptions) TakeServerOptions() ServerOptions {
  323. return ServerOptions(*o)
  324. }
  325. func (o *DNSServerAddressOptions) ReplaceServerOptions(options ServerOptions) {
  326. *o = DNSServerAddressOptions(options)
  327. }
  328. type LegacyDNSServerOptions struct {
  329. Address string `json:"address"`
  330. AddressResolver string `json:"address_resolver,omitempty"`
  331. AddressStrategy DomainStrategy `json:"address_strategy,omitempty"`
  332. AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"`
  333. Strategy DomainStrategy `json:"strategy,omitempty"`
  334. Detour string `json:"detour,omitempty"`
  335. ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
  336. }
  337. type HostsDNSServerOptions struct {
  338. Path badoption.Listable[string] `json:"path,omitempty"`
  339. Predefined *badjson.TypedMap[string, badoption.Listable[netip.Addr]] `json:"predefined,omitempty"`
  340. }
  341. type RawLocalDNSServerOptions struct {
  342. DialerOptions
  343. Legacy bool `json:"-"`
  344. LegacyStrategy DomainStrategy `json:"-"`
  345. LegacyDefaultDialer bool `json:"-"`
  346. LegacyClientSubnet netip.Prefix `json:"-"`
  347. }
  348. type LocalDNSServerOptions struct {
  349. RawLocalDNSServerOptions
  350. PreferGo bool `json:"prefer_go,omitempty"`
  351. }
  352. type RemoteDNSServerOptions struct {
  353. RawLocalDNSServerOptions
  354. DNSServerAddressOptions
  355. LegacyAddressResolver string `json:"-"`
  356. LegacyAddressStrategy DomainStrategy `json:"-"`
  357. LegacyAddressFallbackDelay badoption.Duration `json:"-"`
  358. }
  359. type RemoteTLSDNSServerOptions struct {
  360. RemoteDNSServerOptions
  361. OutboundTLSOptionsContainer
  362. }
  363. type RemoteHTTPSDNSServerOptions struct {
  364. RemoteTLSDNSServerOptions
  365. Path string `json:"path,omitempty"`
  366. Method string `json:"method,omitempty"`
  367. Headers badoption.HTTPHeader `json:"headers,omitempty"`
  368. }
  369. type FakeIPDNSServerOptions struct {
  370. Inet4Range *badoption.Prefix `json:"inet4_range,omitempty"`
  371. Inet6Range *badoption.Prefix `json:"inet6_range,omitempty"`
  372. }
  373. type DHCPDNSServerOptions struct {
  374. LocalDNSServerOptions
  375. Interface string `json:"interface,omitempty"`
  376. }