router.go 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158
  1. package dns
  2. import (
  3. "context"
  4. "errors"
  5. "net/netip"
  6. "strings"
  7. "sync"
  8. "time"
  9. "github.com/sagernet/sing-box/adapter"
  10. "github.com/sagernet/sing-box/common/taskmonitor"
  11. C "github.com/sagernet/sing-box/constant"
  12. "github.com/sagernet/sing-box/experimental/deprecated"
  13. "github.com/sagernet/sing-box/log"
  14. "github.com/sagernet/sing-box/option"
  15. R "github.com/sagernet/sing-box/route/rule"
  16. "github.com/sagernet/sing-tun"
  17. "github.com/sagernet/sing/common"
  18. E "github.com/sagernet/sing/common/exceptions"
  19. F "github.com/sagernet/sing/common/format"
  20. "github.com/sagernet/sing/common/logger"
  21. M "github.com/sagernet/sing/common/metadata"
  22. "github.com/sagernet/sing/common/task"
  23. "github.com/sagernet/sing/contrab/freelru"
  24. "github.com/sagernet/sing/contrab/maphash"
  25. "github.com/sagernet/sing/service"
  26. mDNS "github.com/miekg/dns"
  27. )
  28. var (
  29. _ adapter.DNSRouter = (*Router)(nil)
  30. _ adapter.DNSRuleSetUpdateValidator = (*Router)(nil)
  31. )
  32. type Router struct {
  33. ctx context.Context
  34. logger logger.ContextLogger
  35. transport adapter.DNSTransportManager
  36. outbound adapter.OutboundManager
  37. client adapter.DNSClient
  38. rawRules []option.DNSRule
  39. rules []adapter.DNSRule
  40. defaultDomainStrategy C.DomainStrategy
  41. dnsReverseMapping freelru.Cache[netip.Addr, string]
  42. platformInterface adapter.PlatformInterface
  43. legacyDNSMode bool
  44. rulesAccess sync.RWMutex
  45. started bool
  46. closing bool
  47. }
  48. func NewRouter(ctx context.Context, logFactory log.Factory, options option.DNSOptions) (*Router, error) {
  49. router := &Router{
  50. ctx: ctx,
  51. logger: logFactory.NewLogger("dns"),
  52. transport: service.FromContext[adapter.DNSTransportManager](ctx),
  53. outbound: service.FromContext[adapter.OutboundManager](ctx),
  54. rawRules: make([]option.DNSRule, 0, len(options.Rules)),
  55. rules: make([]adapter.DNSRule, 0, len(options.Rules)),
  56. defaultDomainStrategy: C.DomainStrategy(options.Strategy),
  57. }
  58. if options.DNSClientOptions.IndependentCache {
  59. deprecated.Report(ctx, deprecated.OptionIndependentDNSCache)
  60. }
  61. var optimisticTimeout time.Duration
  62. optimisticOptions := common.PtrValueOrDefault(options.DNSClientOptions.Optimistic)
  63. if optimisticOptions.Enabled {
  64. if options.DNSClientOptions.DisableCache {
  65. return nil, E.New("`optimistic` is conflict with `disable_cache`")
  66. }
  67. if options.DNSClientOptions.DisableExpire {
  68. return nil, E.New("`optimistic` is conflict with `disable_expire`")
  69. }
  70. optimisticTimeout = time.Duration(optimisticOptions.Timeout)
  71. if optimisticTimeout == 0 {
  72. optimisticTimeout = 3 * 24 * time.Hour
  73. }
  74. }
  75. router.client = NewClient(ClientOptions{
  76. Context: ctx,
  77. DisableCache: options.DNSClientOptions.DisableCache,
  78. DisableExpire: options.DNSClientOptions.DisableExpire,
  79. OptimisticTimeout: optimisticTimeout,
  80. CacheCapacity: options.DNSClientOptions.CacheCapacity,
  81. ClientSubnet: options.DNSClientOptions.ClientSubnet.Build(netip.Prefix{}),
  82. RDRC: func() adapter.RDRCStore {
  83. cacheFile := service.FromContext[adapter.CacheFile](ctx)
  84. if cacheFile == nil {
  85. return nil
  86. }
  87. if !cacheFile.StoreRDRC() {
  88. return nil
  89. }
  90. return cacheFile
  91. },
  92. DNSCache: func() adapter.DNSCacheStore {
  93. cacheFile := service.FromContext[adapter.CacheFile](ctx)
  94. if cacheFile == nil {
  95. return nil
  96. }
  97. if !cacheFile.StoreDNS() {
  98. return nil
  99. }
  100. cacheFile.SetDisableExpire(options.DNSClientOptions.DisableExpire)
  101. cacheFile.SetOptimisticTimeout(optimisticTimeout)
  102. return cacheFile
  103. },
  104. Logger: router.logger,
  105. })
  106. if options.ReverseMapping {
  107. router.dnsReverseMapping = common.Must1(freelru.NewSharded[netip.Addr, string](1024, maphash.NewHasher[netip.Addr]().Hash32))
  108. }
  109. return router, nil
  110. }
  111. func (r *Router) Initialize(rules []option.DNSRule) error {
  112. r.rawRules = append(r.rawRules[:0], rules...)
  113. newRules, _, _, err := r.buildRules(false)
  114. if err != nil {
  115. return err
  116. }
  117. closeRules(newRules)
  118. return nil
  119. }
  120. func (r *Router) Start(stage adapter.StartStage) error {
  121. monitor := taskmonitor.New(r.logger, C.StartTimeout)
  122. switch stage {
  123. case adapter.StartStateStart:
  124. monitor.Start("initialize DNS client")
  125. r.client.Start()
  126. monitor.Finish()
  127. monitor.Start("initialize DNS rules")
  128. newRules, legacyDNSMode, modeFlags, err := r.buildRules(true)
  129. monitor.Finish()
  130. if err != nil {
  131. return err
  132. }
  133. r.rulesAccess.Lock()
  134. if r.closing {
  135. r.rulesAccess.Unlock()
  136. closeRules(newRules)
  137. return nil
  138. }
  139. r.rules = newRules
  140. r.legacyDNSMode = legacyDNSMode
  141. r.started = true
  142. r.rulesAccess.Unlock()
  143. if legacyDNSMode && common.Any(newRules, func(rule adapter.DNSRule) bool { return rule.WithAddressLimit() }) {
  144. deprecated.Report(r.ctx, deprecated.OptionLegacyDNSAddressFilter)
  145. }
  146. if legacyDNSMode && modeFlags.neededFromStrategy {
  147. deprecated.Report(r.ctx, deprecated.OptionLegacyDNSRuleStrategy)
  148. }
  149. }
  150. return nil
  151. }
  152. func (r *Router) Close() error {
  153. r.rulesAccess.Lock()
  154. if r.closing {
  155. r.rulesAccess.Unlock()
  156. return nil
  157. }
  158. r.closing = true
  159. runtimeRules := r.rules
  160. r.rules = nil
  161. r.rulesAccess.Unlock()
  162. closeRules(runtimeRules)
  163. return nil
  164. }
  165. func (r *Router) buildRules(startRules bool) ([]adapter.DNSRule, bool, dnsRuleModeFlags, error) {
  166. for i, ruleOptions := range r.rawRules {
  167. err := R.ValidateNoNestedDNSRuleActions(ruleOptions)
  168. if err != nil {
  169. return nil, false, dnsRuleModeFlags{}, E.Cause(err, "parse dns rule[", i, "]")
  170. }
  171. }
  172. router := service.FromContext[adapter.Router](r.ctx)
  173. legacyDNSMode, modeFlags, err := resolveLegacyDNSMode(router, r.rawRules, nil)
  174. if err != nil {
  175. return nil, false, dnsRuleModeFlags{}, err
  176. }
  177. if !legacyDNSMode {
  178. err = validateLegacyDNSModeDisabledRules(router, r.rawRules, nil)
  179. if err != nil {
  180. return nil, false, dnsRuleModeFlags{}, err
  181. }
  182. }
  183. err = validateEvaluateFakeIPRules(r.rawRules, r.transport)
  184. if err != nil {
  185. return nil, false, dnsRuleModeFlags{}, err
  186. }
  187. newRules := make([]adapter.DNSRule, 0, len(r.rawRules))
  188. for i, ruleOptions := range r.rawRules {
  189. var dnsRule adapter.DNSRule
  190. dnsRule, err = R.NewDNSRule(r.ctx, r.logger, ruleOptions, true, legacyDNSMode)
  191. if err != nil {
  192. closeRules(newRules)
  193. return nil, false, dnsRuleModeFlags{}, E.Cause(err, "parse dns rule[", i, "]")
  194. }
  195. newRules = append(newRules, dnsRule)
  196. }
  197. if startRules {
  198. for i, rule := range newRules {
  199. err = rule.Start()
  200. if err != nil {
  201. closeRules(newRules)
  202. return nil, false, dnsRuleModeFlags{}, E.Cause(err, "initialize DNS rule[", i, "]")
  203. }
  204. }
  205. }
  206. return newRules, legacyDNSMode, modeFlags, nil
  207. }
  208. func closeRules(rules []adapter.DNSRule) {
  209. for _, rule := range rules {
  210. _ = rule.Close()
  211. }
  212. }
  213. func (r *Router) ValidateRuleSetMetadataUpdate(tag string, metadata adapter.RuleSetMetadata) error {
  214. if len(r.rawRules) == 0 {
  215. return nil
  216. }
  217. router := service.FromContext[adapter.Router](r.ctx)
  218. if router == nil {
  219. return E.New("router service not found")
  220. }
  221. overrides := map[string]adapter.RuleSetMetadata{
  222. tag: metadata,
  223. }
  224. r.rulesAccess.RLock()
  225. started := r.started
  226. legacyDNSMode := r.legacyDNSMode
  227. closing := r.closing
  228. r.rulesAccess.RUnlock()
  229. if closing {
  230. return nil
  231. }
  232. if !started {
  233. candidateLegacyDNSMode, _, err := resolveLegacyDNSMode(router, r.rawRules, overrides)
  234. if err != nil {
  235. return err
  236. }
  237. if !candidateLegacyDNSMode {
  238. return validateLegacyDNSModeDisabledRules(router, r.rawRules, overrides)
  239. }
  240. return nil
  241. }
  242. candidateLegacyDNSMode, flags, err := resolveLegacyDNSMode(router, r.rawRules, overrides)
  243. if err != nil {
  244. return err
  245. }
  246. if legacyDNSMode {
  247. if !candidateLegacyDNSMode && flags.disabled {
  248. err := validateLegacyDNSModeDisabledRules(router, r.rawRules, overrides)
  249. if err != nil {
  250. return err
  251. }
  252. return E.New(deprecated.OptionLegacyDNSAddressFilter.MessageWithLink())
  253. }
  254. return nil
  255. }
  256. if candidateLegacyDNSMode {
  257. return E.New(deprecated.OptionLegacyDNSAddressFilter.MessageWithLink())
  258. }
  259. return validateLegacyDNSModeDisabledRules(router, r.rawRules, overrides)
  260. }
  261. func (r *Router) matchDNS(ctx context.Context, rules []adapter.DNSRule, allowFakeIP bool, ruleIndex int, isAddressQuery bool, options *adapter.DNSQueryOptions) (adapter.DNSTransport, adapter.DNSRule, int) {
  262. metadata := adapter.ContextFrom(ctx)
  263. if metadata == nil {
  264. panic("no context")
  265. }
  266. var currentRuleIndex int
  267. if ruleIndex != -1 {
  268. currentRuleIndex = ruleIndex + 1
  269. }
  270. for ; currentRuleIndex < len(rules); currentRuleIndex++ {
  271. currentRule := rules[currentRuleIndex]
  272. if currentRule.WithAddressLimit() && !isAddressQuery {
  273. continue
  274. }
  275. metadata.ResetRuleCache()
  276. metadata.DestinationAddressMatchFromResponse = false
  277. if currentRule.LegacyPreMatch(metadata) {
  278. if ruleDescription := currentRule.String(); ruleDescription != "" {
  279. r.logger.DebugContext(ctx, "match[", currentRuleIndex, "] ", currentRule, " => ", currentRule.Action())
  280. } else {
  281. r.logger.DebugContext(ctx, "match[", currentRuleIndex, "] => ", currentRule.Action())
  282. }
  283. switch action := currentRule.Action().(type) {
  284. case *R.RuleActionDNSRoute:
  285. transport, loaded := r.transport.Transport(action.Server)
  286. if !loaded {
  287. r.logger.ErrorContext(ctx, "transport not found: ", action.Server)
  288. continue
  289. }
  290. isFakeIP := transport.Type() == C.DNSTypeFakeIP
  291. if isFakeIP && !allowFakeIP {
  292. continue
  293. }
  294. if action.Strategy != C.DomainStrategyAsIS {
  295. options.Strategy = action.Strategy
  296. }
  297. if isFakeIP || action.DisableCache {
  298. options.DisableCache = true
  299. }
  300. if action.RewriteTTL != nil {
  301. options.RewriteTTL = action.RewriteTTL
  302. }
  303. if action.ClientSubnet.IsValid() {
  304. options.ClientSubnet = action.ClientSubnet
  305. }
  306. return transport, currentRule, currentRuleIndex
  307. case *R.RuleActionDNSRouteOptions:
  308. if action.Strategy != C.DomainStrategyAsIS {
  309. options.Strategy = action.Strategy
  310. }
  311. if action.DisableCache {
  312. options.DisableCache = true
  313. }
  314. if action.RewriteTTL != nil {
  315. options.RewriteTTL = action.RewriteTTL
  316. }
  317. if action.ClientSubnet.IsValid() {
  318. options.ClientSubnet = action.ClientSubnet
  319. }
  320. case *R.RuleActionReject:
  321. return nil, currentRule, currentRuleIndex
  322. case *R.RuleActionPredefined:
  323. return nil, currentRule, currentRuleIndex
  324. }
  325. }
  326. }
  327. transport := r.transport.Default()
  328. return transport, nil, -1
  329. }
  330. func (r *Router) applyDNSRouteOptions(options *adapter.DNSQueryOptions, routeOptions R.RuleActionDNSRouteOptions) {
  331. // Strategy is intentionally skipped here. A non-default DNS rule action strategy
  332. // forces legacy mode via resolveLegacyDNSMode, so this path is only reachable
  333. // when strategy remains at its default value.
  334. if routeOptions.DisableCache {
  335. options.DisableCache = true
  336. }
  337. if routeOptions.DisableOptimisticCache {
  338. options.DisableOptimisticCache = true
  339. }
  340. if routeOptions.RewriteTTL != nil {
  341. options.RewriteTTL = routeOptions.RewriteTTL
  342. }
  343. if routeOptions.ClientSubnet.IsValid() {
  344. options.ClientSubnet = routeOptions.ClientSubnet
  345. }
  346. }
  347. type dnsRouteStatus uint8
  348. const (
  349. dnsRouteStatusMissing dnsRouteStatus = iota
  350. dnsRouteStatusSkipped
  351. dnsRouteStatusResolved
  352. )
  353. func (r *Router) resolveDNSRoute(server string, routeOptions R.RuleActionDNSRouteOptions, allowFakeIP bool, options *adapter.DNSQueryOptions) (adapter.DNSTransport, dnsRouteStatus) {
  354. transport, loaded := r.transport.Transport(server)
  355. if !loaded {
  356. return nil, dnsRouteStatusMissing
  357. }
  358. isFakeIP := transport.Type() == C.DNSTypeFakeIP
  359. if isFakeIP && !allowFakeIP {
  360. return transport, dnsRouteStatusSkipped
  361. }
  362. r.applyDNSRouteOptions(options, routeOptions)
  363. if isFakeIP {
  364. options.DisableCache = true
  365. }
  366. return transport, dnsRouteStatusResolved
  367. }
  368. func (r *Router) logRuleMatch(ctx context.Context, ruleIndex int, currentRule adapter.DNSRule) {
  369. if ruleDescription := currentRule.String(); ruleDescription != "" {
  370. r.logger.DebugContext(ctx, "match[", ruleIndex, "] ", currentRule, " => ", currentRule.Action())
  371. } else {
  372. r.logger.DebugContext(ctx, "match[", ruleIndex, "] => ", currentRule.Action())
  373. }
  374. }
  375. type exchangeWithRulesResult struct {
  376. response *mDNS.Msg
  377. transport adapter.DNSTransport
  378. rejectAction *R.RuleActionReject
  379. err error
  380. }
  381. const dnsRespondMissingResponseMessage = "respond action requires an evaluated response from a preceding evaluate action"
  382. func (r *Router) exchangeWithRules(ctx context.Context, rules []adapter.DNSRule, message *mDNS.Msg, options adapter.DNSQueryOptions, allowFakeIP bool) exchangeWithRulesResult {
  383. metadata := adapter.ContextFrom(ctx)
  384. if metadata == nil {
  385. panic("no context")
  386. }
  387. effectiveOptions := options
  388. var evaluatedResponse *mDNS.Msg
  389. var evaluatedTransport adapter.DNSTransport
  390. for currentRuleIndex, currentRule := range rules {
  391. metadata.ResetRuleCache()
  392. metadata.DNSResponse = evaluatedResponse
  393. metadata.DestinationAddressMatchFromResponse = false
  394. if !currentRule.Match(metadata) {
  395. continue
  396. }
  397. r.logRuleMatch(ctx, currentRuleIndex, currentRule)
  398. switch action := currentRule.Action().(type) {
  399. case *R.RuleActionDNSRouteOptions:
  400. r.applyDNSRouteOptions(&effectiveOptions, *action)
  401. case *R.RuleActionEvaluate:
  402. queryOptions := effectiveOptions
  403. transport, loaded := r.transport.Transport(action.Server)
  404. if !loaded {
  405. r.logger.ErrorContext(ctx, "transport not found: ", action.Server)
  406. evaluatedResponse = nil
  407. evaluatedTransport = nil
  408. continue
  409. }
  410. r.applyDNSRouteOptions(&queryOptions, action.RuleActionDNSRouteOptions)
  411. exchangeOptions := queryOptions
  412. if exchangeOptions.Strategy == C.DomainStrategyAsIS {
  413. exchangeOptions.Strategy = r.defaultDomainStrategy
  414. }
  415. response, err := r.client.Exchange(adapter.OverrideContext(ctx), transport, message, exchangeOptions, nil)
  416. if err != nil {
  417. r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", FormatQuestion(message.Question[0].String())))
  418. evaluatedResponse = nil
  419. evaluatedTransport = nil
  420. continue
  421. }
  422. evaluatedResponse = response
  423. evaluatedTransport = transport
  424. case *R.RuleActionRespond:
  425. if evaluatedResponse == nil {
  426. return exchangeWithRulesResult{
  427. err: E.New(dnsRespondMissingResponseMessage),
  428. }
  429. }
  430. return exchangeWithRulesResult{
  431. response: evaluatedResponse,
  432. transport: evaluatedTransport,
  433. }
  434. case *R.RuleActionDNSRoute:
  435. queryOptions := effectiveOptions
  436. transport, status := r.resolveDNSRoute(action.Server, action.RuleActionDNSRouteOptions, allowFakeIP, &queryOptions)
  437. switch status {
  438. case dnsRouteStatusMissing:
  439. r.logger.ErrorContext(ctx, "transport not found: ", action.Server)
  440. continue
  441. case dnsRouteStatusSkipped:
  442. continue
  443. }
  444. exchangeOptions := queryOptions
  445. if exchangeOptions.Strategy == C.DomainStrategyAsIS {
  446. exchangeOptions.Strategy = r.defaultDomainStrategy
  447. }
  448. response, err := r.client.Exchange(adapter.OverrideContext(ctx), transport, message, exchangeOptions, nil)
  449. return exchangeWithRulesResult{
  450. response: response,
  451. transport: transport,
  452. err: err,
  453. }
  454. case *R.RuleActionReject:
  455. switch action.Method {
  456. case C.RuleActionRejectMethodDefault:
  457. return exchangeWithRulesResult{
  458. response: &mDNS.Msg{
  459. MsgHdr: mDNS.MsgHdr{
  460. Id: message.Id,
  461. Rcode: mDNS.RcodeRefused,
  462. Response: true,
  463. },
  464. Question: []mDNS.Question{message.Question[0]},
  465. },
  466. rejectAction: action,
  467. }
  468. case C.RuleActionRejectMethodDrop:
  469. return exchangeWithRulesResult{
  470. rejectAction: action,
  471. err: tun.ErrDrop,
  472. }
  473. }
  474. case *R.RuleActionPredefined:
  475. return exchangeWithRulesResult{
  476. response: action.Response(message),
  477. }
  478. }
  479. }
  480. transport := r.transport.Default()
  481. exchangeOptions := effectiveOptions
  482. if exchangeOptions.Strategy == C.DomainStrategyAsIS {
  483. exchangeOptions.Strategy = r.defaultDomainStrategy
  484. }
  485. response, err := r.client.Exchange(adapter.OverrideContext(ctx), transport, message, exchangeOptions, nil)
  486. return exchangeWithRulesResult{
  487. response: response,
  488. transport: transport,
  489. err: err,
  490. }
  491. }
  492. func (r *Router) resolveLookupStrategy(options adapter.DNSQueryOptions) C.DomainStrategy {
  493. if options.LookupStrategy != C.DomainStrategyAsIS {
  494. return options.LookupStrategy
  495. }
  496. if options.Strategy != C.DomainStrategyAsIS {
  497. return options.Strategy
  498. }
  499. return r.defaultDomainStrategy
  500. }
  501. func withLookupQueryMetadata(ctx context.Context, qType uint16) context.Context {
  502. ctx, metadata := adapter.ExtendContext(ctx)
  503. metadata.QueryType = qType
  504. metadata.IPVersion = 0
  505. switch qType {
  506. case mDNS.TypeA:
  507. metadata.IPVersion = 4
  508. case mDNS.TypeAAAA:
  509. metadata.IPVersion = 6
  510. }
  511. return ctx
  512. }
  513. func filterAddressesByQueryType(addresses []netip.Addr, qType uint16) []netip.Addr {
  514. switch qType {
  515. case mDNS.TypeA:
  516. return common.Filter(addresses, func(address netip.Addr) bool {
  517. return address.Is4()
  518. })
  519. case mDNS.TypeAAAA:
  520. return common.Filter(addresses, func(address netip.Addr) bool {
  521. return address.Is6()
  522. })
  523. default:
  524. return addresses
  525. }
  526. }
  527. func (r *Router) lookupWithRules(ctx context.Context, rules []adapter.DNSRule, domain string, options adapter.DNSQueryOptions) ([]netip.Addr, error) {
  528. strategy := r.resolveLookupStrategy(options)
  529. lookupOptions := options
  530. if strategy != C.DomainStrategyAsIS {
  531. lookupOptions.Strategy = strategy
  532. }
  533. if strategy == C.DomainStrategyIPv4Only {
  534. return r.lookupWithRulesType(ctx, rules, domain, mDNS.TypeA, lookupOptions)
  535. }
  536. if strategy == C.DomainStrategyIPv6Only {
  537. return r.lookupWithRulesType(ctx, rules, domain, mDNS.TypeAAAA, lookupOptions)
  538. }
  539. var (
  540. response4 []netip.Addr
  541. response6 []netip.Addr
  542. )
  543. var group task.Group
  544. group.Append("exchange4", func(ctx context.Context) error {
  545. result, err := r.lookupWithRulesType(ctx, rules, domain, mDNS.TypeA, lookupOptions)
  546. response4 = result
  547. return err
  548. })
  549. group.Append("exchange6", func(ctx context.Context) error {
  550. result, err := r.lookupWithRulesType(ctx, rules, domain, mDNS.TypeAAAA, lookupOptions)
  551. response6 = result
  552. return err
  553. })
  554. err := group.Run(ctx)
  555. if len(response4) == 0 && len(response6) == 0 {
  556. return nil, err
  557. }
  558. return sortAddresses(response4, response6, strategy), nil
  559. }
  560. func (r *Router) lookupWithRulesType(ctx context.Context, rules []adapter.DNSRule, domain string, qType uint16, options adapter.DNSQueryOptions) ([]netip.Addr, error) {
  561. request := &mDNS.Msg{
  562. MsgHdr: mDNS.MsgHdr{
  563. RecursionDesired: true,
  564. },
  565. Question: []mDNS.Question{{
  566. Name: mDNS.Fqdn(domain),
  567. Qtype: qType,
  568. Qclass: mDNS.ClassINET,
  569. }},
  570. }
  571. exchangeResult := r.exchangeWithRules(withLookupQueryMetadata(ctx, qType), rules, request, options, false)
  572. if exchangeResult.rejectAction != nil {
  573. return nil, exchangeResult.rejectAction.Error(ctx)
  574. }
  575. if exchangeResult.err != nil {
  576. return nil, exchangeResult.err
  577. }
  578. if exchangeResult.response.Rcode != mDNS.RcodeSuccess {
  579. return nil, RcodeError(exchangeResult.response.Rcode)
  580. }
  581. return filterAddressesByQueryType(MessageToAddresses(exchangeResult.response), qType), nil
  582. }
  583. func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg, options adapter.DNSQueryOptions) (*mDNS.Msg, error) {
  584. if len(message.Question) != 1 {
  585. r.logger.WarnContext(ctx, "bad question size: ", len(message.Question))
  586. responseMessage := mDNS.Msg{
  587. MsgHdr: mDNS.MsgHdr{
  588. Id: message.Id,
  589. Response: true,
  590. Rcode: mDNS.RcodeFormatError,
  591. },
  592. Question: message.Question,
  593. }
  594. return &responseMessage, nil
  595. }
  596. r.rulesAccess.RLock()
  597. if r.closing {
  598. r.rulesAccess.RUnlock()
  599. return nil, E.New("dns router closed")
  600. }
  601. rules := r.rules
  602. legacyDNSMode := r.legacyDNSMode
  603. r.rulesAccess.RUnlock()
  604. r.logger.DebugContext(ctx, "exchange ", FormatQuestion(message.Question[0].String()))
  605. var (
  606. response *mDNS.Msg
  607. transport adapter.DNSTransport
  608. err error
  609. )
  610. var metadata *adapter.InboundContext
  611. ctx, metadata = adapter.ExtendContext(ctx)
  612. metadata.Destination = M.Socksaddr{}
  613. metadata.QueryType = message.Question[0].Qtype
  614. metadata.DNSResponse = nil
  615. metadata.DestinationAddressMatchFromResponse = false
  616. switch metadata.QueryType {
  617. case mDNS.TypeA:
  618. metadata.IPVersion = 4
  619. case mDNS.TypeAAAA:
  620. metadata.IPVersion = 6
  621. }
  622. metadata.Domain = FqdnToDomain(message.Question[0].Name)
  623. if options.Transport != nil {
  624. transport = options.Transport
  625. if options.Strategy == C.DomainStrategyAsIS {
  626. options.Strategy = r.defaultDomainStrategy
  627. }
  628. response, err = r.client.Exchange(ctx, transport, message, options, nil)
  629. } else if !legacyDNSMode {
  630. exchangeResult := r.exchangeWithRules(ctx, rules, message, options, true)
  631. response, transport, err = exchangeResult.response, exchangeResult.transport, exchangeResult.err
  632. } else {
  633. var (
  634. rule adapter.DNSRule
  635. ruleIndex int
  636. )
  637. ruleIndex = -1
  638. for {
  639. dnsCtx := adapter.OverrideContext(ctx)
  640. dnsOptions := options
  641. transport, rule, ruleIndex = r.matchDNS(ctx, rules, true, ruleIndex, isAddressQuery(message), &dnsOptions)
  642. if rule != nil {
  643. switch action := rule.Action().(type) {
  644. case *R.RuleActionReject:
  645. switch action.Method {
  646. case C.RuleActionRejectMethodDefault:
  647. return &mDNS.Msg{
  648. MsgHdr: mDNS.MsgHdr{
  649. Id: message.Id,
  650. Rcode: mDNS.RcodeRefused,
  651. Response: true,
  652. },
  653. Question: []mDNS.Question{message.Question[0]},
  654. }, nil
  655. case C.RuleActionRejectMethodDrop:
  656. return nil, tun.ErrDrop
  657. }
  658. case *R.RuleActionPredefined:
  659. err = nil
  660. response = action.Response(message)
  661. goto done
  662. }
  663. }
  664. responseCheck := addressLimitResponseCheck(rule, metadata)
  665. if dnsOptions.Strategy == C.DomainStrategyAsIS {
  666. dnsOptions.Strategy = r.defaultDomainStrategy
  667. }
  668. response, err = r.client.Exchange(dnsCtx, transport, message, dnsOptions, responseCheck)
  669. var rejected bool
  670. if err != nil {
  671. if errors.Is(err, ErrResponseRejectedCached) {
  672. rejected = true
  673. r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String())), " (cached)")
  674. } else if errors.Is(err, ErrResponseRejected) {
  675. rejected = true
  676. r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String())))
  677. } else if len(message.Question) > 0 {
  678. r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", FormatQuestion(message.Question[0].String())))
  679. } else {
  680. r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for <empty query>"))
  681. }
  682. }
  683. if responseCheck != nil && rejected {
  684. continue
  685. }
  686. break
  687. }
  688. }
  689. done:
  690. if err != nil {
  691. return nil, err
  692. }
  693. if r.dnsReverseMapping != nil && len(message.Question) > 0 && response != nil && len(response.Answer) > 0 {
  694. if transport == nil || transport.Type() != C.DNSTypeFakeIP {
  695. for _, answer := range response.Answer {
  696. switch record := answer.(type) {
  697. case *mDNS.A:
  698. r.dnsReverseMapping.AddWithLifetime(M.AddrFromIP(record.A), FqdnToDomain(record.Hdr.Name), time.Duration(record.Hdr.Ttl)*time.Second)
  699. case *mDNS.AAAA:
  700. r.dnsReverseMapping.AddWithLifetime(M.AddrFromIP(record.AAAA), FqdnToDomain(record.Hdr.Name), time.Duration(record.Hdr.Ttl)*time.Second)
  701. }
  702. }
  703. }
  704. }
  705. return response, nil
  706. }
  707. func (r *Router) Lookup(ctx context.Context, domain string, options adapter.DNSQueryOptions) ([]netip.Addr, error) {
  708. r.rulesAccess.RLock()
  709. if r.closing {
  710. r.rulesAccess.RUnlock()
  711. return nil, E.New("dns router closed")
  712. }
  713. rules := r.rules
  714. legacyDNSMode := r.legacyDNSMode
  715. r.rulesAccess.RUnlock()
  716. var (
  717. responseAddrs []netip.Addr
  718. err error
  719. )
  720. printResult := func() {
  721. if err == nil && len(responseAddrs) == 0 {
  722. err = E.New("empty result")
  723. }
  724. if err != nil {
  725. if errors.Is(err, ErrResponseRejectedCached) {
  726. r.logger.DebugContext(ctx, "response rejected for ", domain, " (cached)")
  727. } else if errors.Is(err, ErrResponseRejected) {
  728. r.logger.DebugContext(ctx, "response rejected for ", domain)
  729. } else if R.IsRejected(err) {
  730. r.logger.DebugContext(ctx, "lookup rejected for ", domain)
  731. } else {
  732. r.logger.ErrorContext(ctx, E.Cause(err, "lookup failed for ", domain))
  733. }
  734. }
  735. if err != nil {
  736. err = E.Cause(err, "lookup ", domain)
  737. }
  738. }
  739. r.logger.DebugContext(ctx, "lookup domain ", domain)
  740. ctx, metadata := adapter.ExtendContext(ctx)
  741. metadata.Destination = M.Socksaddr{}
  742. metadata.Domain = FqdnToDomain(domain)
  743. metadata.DNSResponse = nil
  744. metadata.DestinationAddressMatchFromResponse = false
  745. if options.Transport != nil {
  746. transport := options.Transport
  747. if options.Strategy == C.DomainStrategyAsIS {
  748. options.Strategy = r.defaultDomainStrategy
  749. }
  750. responseAddrs, err = r.client.Lookup(ctx, transport, domain, options, nil)
  751. } else if !legacyDNSMode {
  752. responseAddrs, err = r.lookupWithRules(ctx, rules, domain, options)
  753. } else {
  754. var (
  755. transport adapter.DNSTransport
  756. rule adapter.DNSRule
  757. ruleIndex int
  758. )
  759. ruleIndex = -1
  760. for {
  761. dnsCtx := adapter.OverrideContext(ctx)
  762. dnsOptions := options
  763. transport, rule, ruleIndex = r.matchDNS(ctx, rules, false, ruleIndex, true, &dnsOptions)
  764. if rule != nil {
  765. switch action := rule.Action().(type) {
  766. case *R.RuleActionReject:
  767. return nil, &R.RejectedError{Cause: action.Error(ctx)}
  768. case *R.RuleActionPredefined:
  769. responseAddrs = nil
  770. if action.Rcode != mDNS.RcodeSuccess {
  771. err = RcodeError(action.Rcode)
  772. } else {
  773. err = nil
  774. for _, answer := range action.Answer {
  775. switch record := answer.(type) {
  776. case *mDNS.A:
  777. responseAddrs = append(responseAddrs, M.AddrFromIP(record.A))
  778. case *mDNS.AAAA:
  779. responseAddrs = append(responseAddrs, M.AddrFromIP(record.AAAA))
  780. }
  781. }
  782. }
  783. goto response
  784. }
  785. }
  786. responseCheck := addressLimitResponseCheck(rule, metadata)
  787. if dnsOptions.Strategy == C.DomainStrategyAsIS {
  788. dnsOptions.Strategy = r.defaultDomainStrategy
  789. }
  790. responseAddrs, err = r.client.Lookup(dnsCtx, transport, domain, dnsOptions, responseCheck)
  791. if responseCheck == nil || err == nil {
  792. break
  793. }
  794. printResult()
  795. }
  796. }
  797. response:
  798. printResult()
  799. if len(responseAddrs) > 0 {
  800. r.logger.InfoContext(ctx, "lookup succeed for ", domain, ": ", strings.Join(F.MapToString(responseAddrs), " "))
  801. }
  802. return responseAddrs, err
  803. }
  804. func isAddressQuery(message *mDNS.Msg) bool {
  805. for _, question := range message.Question {
  806. if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA || question.Qtype == mDNS.TypeHTTPS {
  807. return true
  808. }
  809. }
  810. return false
  811. }
  812. func addressLimitResponseCheck(rule adapter.DNSRule, metadata *adapter.InboundContext) func(response *mDNS.Msg) bool {
  813. if rule == nil || !rule.WithAddressLimit() {
  814. return nil
  815. }
  816. responseMetadata := *metadata
  817. return func(response *mDNS.Msg) bool {
  818. checkMetadata := responseMetadata
  819. return rule.MatchAddressLimit(&checkMetadata, response)
  820. }
  821. }
  822. func (r *Router) ClearCache() {
  823. r.client.ClearCache()
  824. if r.platformInterface != nil {
  825. r.platformInterface.ClearDNSCache()
  826. }
  827. }
  828. func (r *Router) LookupReverseMapping(ip netip.Addr) (string, bool) {
  829. if r.dnsReverseMapping == nil {
  830. return "", false
  831. }
  832. domain, loaded := r.dnsReverseMapping.Get(ip)
  833. return domain, loaded
  834. }
  835. func (r *Router) ResetNetwork() {
  836. r.ClearCache()
  837. for _, transport := range r.transport.Transports() {
  838. transport.Reset()
  839. }
  840. }
  841. func defaultRuleNeedsLegacyDNSModeFromAddressFilter(rule option.DefaultDNSRule) bool {
  842. if rule.RuleSetIPCIDRAcceptEmpty { //nolint:staticcheck
  843. return true
  844. }
  845. return !rule.MatchResponse && (rule.IPAcceptAny || len(rule.IPCIDR) > 0 || rule.IPIsPrivate)
  846. }
  847. func hasResponseMatchFields(rule option.DefaultDNSRule) bool {
  848. return rule.ResponseRcode != nil ||
  849. len(rule.ResponseAnswer) > 0 ||
  850. len(rule.ResponseNs) > 0 ||
  851. len(rule.ResponseExtra) > 0
  852. }
  853. func defaultRuleDisablesLegacyDNSMode(rule option.DefaultDNSRule) bool {
  854. return rule.MatchResponse ||
  855. hasResponseMatchFields(rule) ||
  856. rule.Action == C.RuleActionTypeEvaluate ||
  857. rule.Action == C.RuleActionTypeRespond ||
  858. rule.IPVersion > 0 ||
  859. len(rule.QueryType) > 0
  860. }
  861. type dnsRuleModeFlags struct {
  862. disabled bool
  863. needed bool
  864. neededFromStrategy bool
  865. }
  866. func (f *dnsRuleModeFlags) merge(other dnsRuleModeFlags) {
  867. f.disabled = f.disabled || other.disabled
  868. f.needed = f.needed || other.needed
  869. f.neededFromStrategy = f.neededFromStrategy || other.neededFromStrategy
  870. }
  871. func resolveLegacyDNSMode(router adapter.Router, rules []option.DNSRule, metadataOverrides map[string]adapter.RuleSetMetadata) (bool, dnsRuleModeFlags, error) {
  872. flags, err := dnsRuleModeRequirements(router, rules, metadataOverrides)
  873. if err != nil {
  874. return false, flags, err
  875. }
  876. if flags.disabled && flags.neededFromStrategy {
  877. return false, flags, E.New(deprecated.OptionLegacyDNSRuleStrategy.MessageWithLink())
  878. }
  879. if flags.disabled {
  880. return false, flags, nil
  881. }
  882. return flags.needed, flags, nil
  883. }
  884. func dnsRuleModeRequirements(router adapter.Router, rules []option.DNSRule, metadataOverrides map[string]adapter.RuleSetMetadata) (dnsRuleModeFlags, error) {
  885. var flags dnsRuleModeFlags
  886. for i, rule := range rules {
  887. ruleFlags, err := dnsRuleModeRequirementsInRule(router, rule, metadataOverrides)
  888. if err != nil {
  889. return dnsRuleModeFlags{}, E.Cause(err, "dns rule[", i, "]")
  890. }
  891. flags.merge(ruleFlags)
  892. }
  893. return flags, nil
  894. }
  895. func dnsRuleModeRequirementsInRule(router adapter.Router, rule option.DNSRule, metadataOverrides map[string]adapter.RuleSetMetadata) (dnsRuleModeFlags, error) {
  896. switch rule.Type {
  897. case "", C.RuleTypeDefault:
  898. return dnsRuleModeRequirementsInDefaultRule(router, rule.DefaultOptions, metadataOverrides)
  899. case C.RuleTypeLogical:
  900. flags := dnsRuleModeFlags{
  901. disabled: dnsRuleActionType(rule) == C.RuleActionTypeEvaluate ||
  902. dnsRuleActionType(rule) == C.RuleActionTypeRespond ||
  903. dnsRuleActionDisablesLegacyDNSMode(rule.LogicalOptions.DNSRuleAction),
  904. neededFromStrategy: dnsRuleActionHasStrategy(rule.LogicalOptions.DNSRuleAction),
  905. }
  906. flags.needed = flags.neededFromStrategy
  907. for i, subRule := range rule.LogicalOptions.Rules {
  908. subFlags, err := dnsRuleModeRequirementsInRule(router, subRule, metadataOverrides)
  909. if err != nil {
  910. return dnsRuleModeFlags{}, E.Cause(err, "sub rule[", i, "]")
  911. }
  912. flags.merge(subFlags)
  913. }
  914. return flags, nil
  915. default:
  916. return dnsRuleModeFlags{}, nil
  917. }
  918. }
  919. func dnsRuleModeRequirementsInDefaultRule(router adapter.Router, rule option.DefaultDNSRule, metadataOverrides map[string]adapter.RuleSetMetadata) (dnsRuleModeFlags, error) {
  920. flags := dnsRuleModeFlags{
  921. disabled: defaultRuleDisablesLegacyDNSMode(rule) || dnsRuleActionDisablesLegacyDNSMode(rule.DNSRuleAction),
  922. neededFromStrategy: dnsRuleActionHasStrategy(rule.DNSRuleAction),
  923. }
  924. flags.needed = defaultRuleNeedsLegacyDNSModeFromAddressFilter(rule) || flags.neededFromStrategy
  925. if len(rule.RuleSet) == 0 {
  926. return flags, nil
  927. }
  928. if router == nil {
  929. return dnsRuleModeFlags{}, E.New("router service not found")
  930. }
  931. for _, tag := range rule.RuleSet {
  932. metadata, err := lookupDNSRuleSetMetadata(router, tag, metadataOverrides)
  933. if err != nil {
  934. return dnsRuleModeFlags{}, err
  935. }
  936. // ip_version is not a headless-rule item, so ContainsIPVersionRule is intentionally absent.
  937. flags.disabled = flags.disabled || metadata.ContainsDNSQueryTypeRule
  938. if !rule.RuleSetIPCIDRMatchSource && metadata.ContainsIPCIDRRule {
  939. flags.needed = true
  940. }
  941. }
  942. return flags, nil
  943. }
  944. func lookupDNSRuleSetMetadata(router adapter.Router, tag string, metadataOverrides map[string]adapter.RuleSetMetadata) (adapter.RuleSetMetadata, error) {
  945. if metadataOverrides != nil {
  946. if metadata, loaded := metadataOverrides[tag]; loaded {
  947. return metadata, nil
  948. }
  949. }
  950. ruleSet, loaded := router.RuleSet(tag)
  951. if !loaded {
  952. return adapter.RuleSetMetadata{}, E.New("rule-set not found: ", tag)
  953. }
  954. return ruleSet.Metadata(), nil
  955. }
  956. func referencedDNSRuleSetTags(rules []option.DNSRule) []string {
  957. tagMap := make(map[string]bool)
  958. var walkRule func(rule option.DNSRule)
  959. walkRule = func(rule option.DNSRule) {
  960. switch rule.Type {
  961. case "", C.RuleTypeDefault:
  962. for _, tag := range rule.DefaultOptions.RuleSet {
  963. tagMap[tag] = true
  964. }
  965. case C.RuleTypeLogical:
  966. for _, subRule := range rule.LogicalOptions.Rules {
  967. walkRule(subRule)
  968. }
  969. }
  970. }
  971. for _, rule := range rules {
  972. walkRule(rule)
  973. }
  974. tags := make([]string, 0, len(tagMap))
  975. for tag := range tagMap {
  976. if tag != "" {
  977. tags = append(tags, tag)
  978. }
  979. }
  980. return tags
  981. }
  982. func validateLegacyDNSModeDisabledRules(router adapter.Router, rules []option.DNSRule, metadataOverrides map[string]adapter.RuleSetMetadata) error {
  983. var seenEvaluate bool
  984. for i, rule := range rules {
  985. requiresPriorEvaluate, err := validateLegacyDNSModeDisabledRuleTree(router, rule, metadataOverrides)
  986. if err != nil {
  987. return E.Cause(err, "validate dns rule[", i, "]")
  988. }
  989. if requiresPriorEvaluate && !seenEvaluate {
  990. return E.New("dns rule[", i, "]: response-based matching requires a preceding evaluate action")
  991. }
  992. if dnsRuleActionType(rule) == C.RuleActionTypeEvaluate {
  993. seenEvaluate = true
  994. }
  995. }
  996. return nil
  997. }
  998. func validateEvaluateFakeIPRules(rules []option.DNSRule, transportManager adapter.DNSTransportManager) error {
  999. if transportManager == nil {
  1000. return nil
  1001. }
  1002. for i, rule := range rules {
  1003. if dnsRuleActionType(rule) != C.RuleActionTypeEvaluate {
  1004. continue
  1005. }
  1006. server := dnsRuleActionServer(rule)
  1007. if server == "" {
  1008. continue
  1009. }
  1010. transport, loaded := transportManager.Transport(server)
  1011. if !loaded || transport.Type() != C.DNSTypeFakeIP {
  1012. continue
  1013. }
  1014. return E.New("dns rule[", i, "]: evaluate action cannot use fakeip server: ", server)
  1015. }
  1016. return nil
  1017. }
  1018. func validateLegacyDNSModeDisabledRuleTree(router adapter.Router, rule option.DNSRule, metadataOverrides map[string]adapter.RuleSetMetadata) (bool, error) {
  1019. switch rule.Type {
  1020. case "", C.RuleTypeDefault:
  1021. return validateLegacyDNSModeDisabledDefaultRule(router, rule.DefaultOptions, metadataOverrides)
  1022. case C.RuleTypeLogical:
  1023. requiresPriorEvaluate := dnsRuleActionType(rule) == C.RuleActionTypeRespond
  1024. for i, subRule := range rule.LogicalOptions.Rules {
  1025. subRequiresPriorEvaluate, err := validateLegacyDNSModeDisabledRuleTree(router, subRule, metadataOverrides)
  1026. if err != nil {
  1027. return false, E.Cause(err, "sub rule[", i, "]")
  1028. }
  1029. requiresPriorEvaluate = requiresPriorEvaluate || subRequiresPriorEvaluate
  1030. }
  1031. return requiresPriorEvaluate, nil
  1032. default:
  1033. return false, nil
  1034. }
  1035. }
  1036. func validateLegacyDNSModeDisabledDefaultRule(router adapter.Router, rule option.DefaultDNSRule, metadataOverrides map[string]adapter.RuleSetMetadata) (bool, error) {
  1037. hasResponseRecords := hasResponseMatchFields(rule)
  1038. if (hasResponseRecords || len(rule.IPCIDR) > 0 || rule.IPIsPrivate || rule.IPAcceptAny) && !rule.MatchResponse {
  1039. return false, E.New("Response Match Fields (ip_cidr, ip_is_private, ip_accept_any, response_rcode, response_answer, response_ns, response_extra) require match_response to be enabled")
  1040. }
  1041. // rule_set entries are only rejected when every referenced set is pure-IP;
  1042. // mixed sets still fall through because their non-IP branches remain matchable
  1043. // before a DNS response is available.
  1044. if !rule.MatchResponse && len(rule.RuleSet) > 0 {
  1045. for _, tag := range rule.RuleSet {
  1046. metadata, err := lookupDNSRuleSetMetadata(router, tag, metadataOverrides)
  1047. if err != nil {
  1048. return false, err
  1049. }
  1050. if metadata.ContainsIPCIDRRule && !metadata.ContainsNonIPCIDRRule {
  1051. return false, E.New(deprecated.OptionLegacyDNSAddressFilter.MessageWithLink())
  1052. }
  1053. }
  1054. }
  1055. if rule.RuleSetIPCIDRAcceptEmpty { //nolint:staticcheck
  1056. return false, E.New(deprecated.OptionRuleSetIPCIDRAcceptEmpty.MessageWithLink())
  1057. }
  1058. return rule.MatchResponse || rule.Action == C.RuleActionTypeRespond, nil
  1059. }
  1060. func dnsRuleActionDisablesLegacyDNSMode(action option.DNSRuleAction) bool {
  1061. switch action.Action {
  1062. case "", C.RuleActionTypeRoute, C.RuleActionTypeEvaluate:
  1063. return action.RouteOptions.DisableOptimisticCache
  1064. case C.RuleActionTypeRouteOptions:
  1065. return action.RouteOptionsOptions.DisableOptimisticCache
  1066. default:
  1067. return false
  1068. }
  1069. }
  1070. func dnsRuleActionHasStrategy(action option.DNSRuleAction) bool {
  1071. switch action.Action {
  1072. case "", C.RuleActionTypeRoute, C.RuleActionTypeEvaluate:
  1073. return C.DomainStrategy(action.RouteOptions.Strategy) != C.DomainStrategyAsIS
  1074. case C.RuleActionTypeRouteOptions:
  1075. return C.DomainStrategy(action.RouteOptionsOptions.Strategy) != C.DomainStrategyAsIS
  1076. default:
  1077. return false
  1078. }
  1079. }
  1080. func dnsRuleActionType(rule option.DNSRule) string {
  1081. switch rule.Type {
  1082. case "", C.RuleTypeDefault:
  1083. if rule.DefaultOptions.Action == "" {
  1084. return C.RuleActionTypeRoute
  1085. }
  1086. return rule.DefaultOptions.Action
  1087. case C.RuleTypeLogical:
  1088. if rule.LogicalOptions.Action == "" {
  1089. return C.RuleActionTypeRoute
  1090. }
  1091. return rule.LogicalOptions.Action
  1092. default:
  1093. return ""
  1094. }
  1095. }
  1096. func dnsRuleActionServer(rule option.DNSRule) string {
  1097. switch rule.Type {
  1098. case "", C.RuleTypeDefault:
  1099. return rule.DefaultOptions.RouteOptions.Server
  1100. case C.RuleTypeLogical:
  1101. return rule.LogicalOptions.RouteOptions.Server
  1102. default:
  1103. return ""
  1104. }
  1105. }