123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- package route
- import (
- "context"
- "os"
- "runtime"
- "github.com/sagernet/sing-box/adapter"
- "github.com/sagernet/sing-box/common/process"
- "github.com/sagernet/sing-box/common/taskmonitor"
- C "github.com/sagernet/sing-box/constant"
- "github.com/sagernet/sing-box/experimental/libbox/platform"
- "github.com/sagernet/sing-box/log"
- "github.com/sagernet/sing-box/option"
- R "github.com/sagernet/sing-box/route/rule"
- E "github.com/sagernet/sing/common/exceptions"
- "github.com/sagernet/sing/common/task"
- "github.com/sagernet/sing/service"
- "github.com/sagernet/sing/service/pause"
- )
- var _ adapter.Router = (*Router)(nil)
- type Router struct {
- ctx context.Context
- logger log.ContextLogger
- inbound adapter.InboundManager
- outbound adapter.OutboundManager
- dns adapter.DNSRouter
- dnsTransport adapter.DNSTransportManager
- connection adapter.ConnectionManager
- network adapter.NetworkManager
- rules []adapter.Rule
- needFindProcess bool
- ruleSets []adapter.RuleSet
- ruleSetMap map[string]adapter.RuleSet
- processSearcher process.Searcher
- pauseManager pause.Manager
- trackers []adapter.ConnectionTracker
- platformInterface platform.Interface
- needWIFIState bool
- started bool
- }
- func NewRouter(ctx context.Context, logFactory log.Factory, options option.RouteOptions, dnsOptions option.DNSOptions) *Router {
- return &Router{
- ctx: ctx,
- logger: logFactory.NewLogger("router"),
- inbound: service.FromContext[adapter.InboundManager](ctx),
- outbound: service.FromContext[adapter.OutboundManager](ctx),
- dns: service.FromContext[adapter.DNSRouter](ctx),
- dnsTransport: service.FromContext[adapter.DNSTransportManager](ctx),
- connection: service.FromContext[adapter.ConnectionManager](ctx),
- network: service.FromContext[adapter.NetworkManager](ctx),
- rules: make([]adapter.Rule, 0, len(options.Rules)),
- ruleSetMap: make(map[string]adapter.RuleSet),
- needFindProcess: hasRule(options.Rules, isProcessRule) || hasDNSRule(dnsOptions.Rules, isProcessDNSRule) || options.FindProcess,
- pauseManager: service.FromContext[pause.Manager](ctx),
- platformInterface: service.FromContext[platform.Interface](ctx),
- needWIFIState: hasRule(options.Rules, isWIFIRule) || hasDNSRule(dnsOptions.Rules, isWIFIDNSRule),
- }
- }
- func (r *Router) Initialize(rules []option.Rule, ruleSets []option.RuleSet) error {
- for i, options := range rules {
- rule, err := R.NewRule(r.ctx, r.logger, options, false)
- if err != nil {
- return E.Cause(err, "parse rule[", i, "]")
- }
- r.rules = append(r.rules, rule)
- }
- for i, options := range ruleSets {
- if _, exists := r.ruleSetMap[options.Tag]; exists {
- return E.New("duplicate rule-set tag: ", options.Tag)
- }
- ruleSet, err := R.NewRuleSet(r.ctx, r.logger, options)
- if err != nil {
- return E.Cause(err, "parse rule-set[", i, "]")
- }
- r.ruleSets = append(r.ruleSets, ruleSet)
- r.ruleSetMap[options.Tag] = ruleSet
- }
- return nil
- }
- func (r *Router) Start(stage adapter.StartStage) error {
- monitor := taskmonitor.New(r.logger, C.StartTimeout)
- switch stage {
- case adapter.StartStateStart:
- var cacheContext *adapter.HTTPStartContext
- if len(r.ruleSets) > 0 {
- monitor.Start("initialize rule-set")
- cacheContext = adapter.NewHTTPStartContext(r.ctx)
- var ruleSetStartGroup task.Group
- for i, ruleSet := range r.ruleSets {
- ruleSetInPlace := ruleSet
- ruleSetStartGroup.Append0(func(ctx context.Context) error {
- err := ruleSetInPlace.StartContext(ctx, cacheContext)
- if err != nil {
- return E.Cause(err, "initialize rule-set[", i, "]")
- }
- return nil
- })
- }
- ruleSetStartGroup.Concurrency(5)
- ruleSetStartGroup.FastFail()
- err := ruleSetStartGroup.Run(r.ctx)
- monitor.Finish()
- if err != nil {
- return err
- }
- }
- if cacheContext != nil {
- cacheContext.Close()
- }
- needFindProcess := r.needFindProcess
- for _, ruleSet := range r.ruleSets {
- metadata := ruleSet.Metadata()
- if metadata.ContainsProcessRule {
- needFindProcess = true
- }
- if metadata.ContainsWIFIRule {
- r.needWIFIState = true
- }
- }
- if needFindProcess {
- if r.platformInterface != nil {
- r.processSearcher = r.platformInterface
- } else {
- monitor.Start("initialize process searcher")
- searcher, err := process.NewSearcher(process.Config{
- Logger: r.logger,
- PackageManager: r.network.PackageManager(),
- })
- monitor.Finish()
- if err != nil {
- if err != os.ErrInvalid {
- r.logger.Warn(E.Cause(err, "create process searcher"))
- }
- } else {
- r.processSearcher = searcher
- }
- }
- }
- case adapter.StartStatePostStart:
- for i, rule := range r.rules {
- monitor.Start("initialize rule[", i, "]")
- err := rule.Start()
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "initialize rule[", i, "]")
- }
- }
- for _, ruleSet := range r.ruleSets {
- monitor.Start("post start rule_set[", ruleSet.Name(), "]")
- err := ruleSet.PostStart()
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "post start rule_set[", ruleSet.Name(), "]")
- }
- }
- r.started = true
- return nil
- case adapter.StartStateStarted:
- for _, ruleSet := range r.ruleSets {
- ruleSet.Cleanup()
- }
- runtime.GC()
- }
- return nil
- }
- func (r *Router) Close() error {
- monitor := taskmonitor.New(r.logger, C.StopTimeout)
- var err error
- for i, rule := range r.rules {
- monitor.Start("close rule[", i, "]")
- err = E.Append(err, rule.Close(), func(err error) error {
- return E.Cause(err, "close rule[", i, "]")
- })
- monitor.Finish()
- }
- for i, ruleSet := range r.ruleSets {
- monitor.Start("close rule-set[", i, "]")
- err = E.Append(err, ruleSet.Close(), func(err error) error {
- return E.Cause(err, "close rule-set[", i, "]")
- })
- monitor.Finish()
- }
- return err
- }
- func (r *Router) RuleSet(tag string) (adapter.RuleSet, bool) {
- ruleSet, loaded := r.ruleSetMap[tag]
- return ruleSet, loaded
- }
- func (r *Router) NeedWIFIState() bool {
- return r.needWIFIState
- }
- func (r *Router) Rules() []adapter.Rule {
- return r.rules
- }
- func (r *Router) AppendTracker(tracker adapter.ConnectionTracker) {
- r.trackers = append(r.trackers, tracker)
- }
- func (r *Router) ResetNetwork() {
- r.network.ResetNetwork()
- r.dns.ResetNetwork()
- }
|