dns.go 9.9 KB

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