dns.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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 outbound 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, (*_Outbound)(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.Addr.String()
  167. if serverAddr.Port != 0 && serverAddr.Port != 53 {
  168. remoteOptions.ServerPort = serverAddr.Port
  169. }
  170. remoteOptions.Server = serverAddr.AddrString()
  171. remoteOptions.ServerPort = serverAddr.Port
  172. case C.DNSTypeTCP:
  173. o.Type = C.DNSTypeTCP
  174. o.Options = &remoteOptions
  175. serverAddr := M.ParseSocksaddr(serverURL.Host)
  176. if !serverAddr.IsValid() {
  177. return E.New("invalid server address")
  178. }
  179. remoteOptions.Server = serverAddr.Addr.String()
  180. if serverAddr.Port != 0 && serverAddr.Port != 53 {
  181. remoteOptions.ServerPort = serverAddr.Port
  182. }
  183. remoteOptions.Server = serverAddr.AddrString()
  184. remoteOptions.ServerPort = serverAddr.Port
  185. case C.DNSTypeTLS, C.DNSTypeQUIC:
  186. o.Type = serverType
  187. serverAddr := M.ParseSocksaddr(serverURL.Host)
  188. if !serverAddr.IsValid() {
  189. return E.New("invalid server address")
  190. }
  191. remoteOptions.Server = serverAddr.Addr.String()
  192. if serverAddr.Port != 0 && serverAddr.Port != 853 {
  193. remoteOptions.ServerPort = serverAddr.Port
  194. }
  195. o.Options = &RemoteTLSDNSServerOptions{
  196. RemoteDNSServerOptions: remoteOptions,
  197. }
  198. case C.DNSTypeHTTPS, C.DNSTypeHTTP3:
  199. o.Type = serverType
  200. httpsOptions := RemoteHTTPSDNSServerOptions{
  201. RemoteTLSDNSServerOptions: RemoteTLSDNSServerOptions{
  202. RemoteDNSServerOptions: remoteOptions,
  203. },
  204. }
  205. o.Options = &httpsOptions
  206. serverAddr := M.ParseSocksaddr(serverURL.Host)
  207. if !serverAddr.IsValid() {
  208. return E.New("invalid server address")
  209. }
  210. httpsOptions.Server = serverAddr.Addr.String()
  211. if serverAddr.Port != 0 && serverAddr.Port != 443 {
  212. httpsOptions.ServerPort = serverAddr.Port
  213. }
  214. if serverURL.Path != "/dns-query" {
  215. httpsOptions.Path = serverURL.Path
  216. }
  217. case "rcode":
  218. var rcode int
  219. switch serverURL.Host {
  220. case "success":
  221. rcode = dns.RcodeSuccess
  222. case "format_error":
  223. rcode = dns.RcodeFormatError
  224. case "server_failure":
  225. rcode = dns.RcodeServerFailure
  226. case "name_error":
  227. rcode = dns.RcodeNameError
  228. case "not_implemented":
  229. rcode = dns.RcodeNotImplemented
  230. case "refused":
  231. rcode = dns.RcodeRefused
  232. default:
  233. return E.New("unknown rcode: ", serverURL.Host)
  234. }
  235. o.Type = C.DNSTypePreDefined
  236. o.Options = &PredefinedDNSServerOptions{
  237. Responses: []DNSResponseOptions{
  238. {
  239. RCode: common.Ptr(DNSRCode(rcode)),
  240. },
  241. },
  242. }
  243. case C.DNSTypeDHCP:
  244. o.Type = C.DNSTypeDHCP
  245. dhcpOptions := DHCPDNSServerOptions{}
  246. if serverURL.Host != "" && serverURL.Host != "auto" {
  247. dhcpOptions.Interface = serverURL.Host
  248. }
  249. o.Options = &dhcpOptions
  250. case C.DNSTypeFakeIP:
  251. o.Type = C.DNSTypeFakeIP
  252. fakeipOptions := FakeIPDNSServerOptions{}
  253. if legacyOptions, loaded := ctx.Value((*LegacyDNSFakeIPOptions)(nil)).(*LegacyDNSFakeIPOptions); loaded {
  254. fakeipOptions.Inet4Range = legacyOptions.Inet4Range
  255. fakeipOptions.Inet6Range = legacyOptions.Inet6Range
  256. }
  257. o.Options = &fakeipOptions
  258. default:
  259. return E.New("unsupported DNS server scheme: ", serverType)
  260. }
  261. return nil
  262. }
  263. type LegacyDNSServerOptions struct {
  264. Address string `json:"address"`
  265. AddressResolver string `json:"address_resolver,omitempty"`
  266. AddressStrategy DomainStrategy `json:"address_strategy,omitempty"`
  267. AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"`
  268. Strategy DomainStrategy `json:"strategy,omitempty"`
  269. Detour string `json:"detour,omitempty"`
  270. ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
  271. }
  272. type HostsDNSServerOptions struct {
  273. Path badoption.Listable[string] `json:"path,omitempty"`
  274. Predefined badjson.TypedMap[string, badoption.Listable[netip.Addr]] `json:"predefined,omitempty"`
  275. }
  276. type LocalDNSServerOptions struct {
  277. DialerOptions
  278. LegacyStrategy DomainStrategy `json:"-"`
  279. LegacyDefaultDialer bool `json:"-"`
  280. LegacyClientSubnet netip.Prefix `json:"-"`
  281. }
  282. type RemoteDNSServerOptions struct {
  283. LocalDNSServerOptions
  284. ServerOptions
  285. LegacyAddressResolver string `json:"-"`
  286. LegacyAddressStrategy DomainStrategy `json:"-"`
  287. LegacyAddressFallbackDelay badoption.Duration `json:"-"`
  288. }
  289. type RemoteTLSDNSServerOptions struct {
  290. RemoteDNSServerOptions
  291. OutboundTLSOptionsContainer
  292. }
  293. type RemoteHTTPSDNSServerOptions struct {
  294. RemoteTLSDNSServerOptions
  295. Path string `json:"path,omitempty"`
  296. Method string `json:"method,omitempty"`
  297. Headers badoption.HTTPHeader `json:"headers,omitempty"`
  298. }
  299. type FakeIPDNSServerOptions struct {
  300. Inet4Range *badoption.Prefix `json:"inet4_range,omitempty"`
  301. Inet6Range *badoption.Prefix `json:"inet6_range,omitempty"`
  302. }
  303. type DHCPDNSServerOptions struct {
  304. LocalDNSServerOptions
  305. Interface string `json:"interface,omitempty"`
  306. }