box.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. package box
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "os"
  7. "runtime/debug"
  8. "time"
  9. "github.com/sagernet/sing-box/adapter"
  10. "github.com/sagernet/sing-box/adapter/endpoint"
  11. "github.com/sagernet/sing-box/adapter/inbound"
  12. "github.com/sagernet/sing-box/adapter/outbound"
  13. "github.com/sagernet/sing-box/common/certificate"
  14. "github.com/sagernet/sing-box/common/dialer"
  15. "github.com/sagernet/sing-box/common/taskmonitor"
  16. "github.com/sagernet/sing-box/common/tls"
  17. C "github.com/sagernet/sing-box/constant"
  18. "github.com/sagernet/sing-box/dns"
  19. "github.com/sagernet/sing-box/dns/transport/local"
  20. "github.com/sagernet/sing-box/experimental"
  21. "github.com/sagernet/sing-box/experimental/cachefile"
  22. "github.com/sagernet/sing-box/experimental/libbox/platform"
  23. "github.com/sagernet/sing-box/log"
  24. "github.com/sagernet/sing-box/mitm"
  25. "github.com/sagernet/sing-box/option"
  26. "github.com/sagernet/sing-box/protocol/direct"
  27. "github.com/sagernet/sing-box/route"
  28. "github.com/sagernet/sing-box/script"
  29. "github.com/sagernet/sing/common"
  30. E "github.com/sagernet/sing/common/exceptions"
  31. F "github.com/sagernet/sing/common/format"
  32. "github.com/sagernet/sing/common/ntp"
  33. "github.com/sagernet/sing/service"
  34. "github.com/sagernet/sing/service/pause"
  35. )
  36. var _ adapter.Service = (*Box)(nil)
  37. type Box struct {
  38. createdAt time.Time
  39. logFactory log.Factory
  40. logger log.ContextLogger
  41. network *route.NetworkManager
  42. endpoint *endpoint.Manager
  43. inbound *inbound.Manager
  44. outbound *outbound.Manager
  45. dnsTransport *dns.TransportManager
  46. dnsRouter *dns.Router
  47. connection *route.ConnectionManager
  48. router *route.Router
  49. script *script.Manager
  50. mitm adapter.MITMEngine //*mitm.Engine
  51. services []adapter.LifecycleService
  52. done chan struct{}
  53. }
  54. type Options struct {
  55. option.Options
  56. Context context.Context
  57. PlatformLogWriter log.PlatformWriter
  58. }
  59. func Context(
  60. ctx context.Context,
  61. inboundRegistry adapter.InboundRegistry,
  62. outboundRegistry adapter.OutboundRegistry,
  63. endpointRegistry adapter.EndpointRegistry,
  64. dnsTransportRegistry adapter.DNSTransportRegistry,
  65. ) context.Context {
  66. if service.FromContext[option.InboundOptionsRegistry](ctx) == nil ||
  67. service.FromContext[adapter.InboundRegistry](ctx) == nil {
  68. ctx = service.ContextWith[option.InboundOptionsRegistry](ctx, inboundRegistry)
  69. ctx = service.ContextWith[adapter.InboundRegistry](ctx, inboundRegistry)
  70. }
  71. if service.FromContext[option.OutboundOptionsRegistry](ctx) == nil ||
  72. service.FromContext[adapter.OutboundRegistry](ctx) == nil {
  73. ctx = service.ContextWith[option.OutboundOptionsRegistry](ctx, outboundRegistry)
  74. ctx = service.ContextWith[adapter.OutboundRegistry](ctx, outboundRegistry)
  75. }
  76. if service.FromContext[option.EndpointOptionsRegistry](ctx) == nil ||
  77. service.FromContext[adapter.EndpointRegistry](ctx) == nil {
  78. ctx = service.ContextWith[option.EndpointOptionsRegistry](ctx, endpointRegistry)
  79. ctx = service.ContextWith[adapter.EndpointRegistry](ctx, endpointRegistry)
  80. }
  81. if service.FromContext[adapter.DNSTransportRegistry](ctx) == nil {
  82. ctx = service.ContextWith[option.DNSTransportOptionsRegistry](ctx, dnsTransportRegistry)
  83. ctx = service.ContextWith[adapter.DNSTransportRegistry](ctx, dnsTransportRegistry)
  84. }
  85. return ctx
  86. }
  87. func New(options Options) (*Box, error) {
  88. createdAt := time.Now()
  89. ctx := options.Context
  90. if ctx == nil {
  91. ctx = context.Background()
  92. }
  93. ctx = service.ContextWithDefaultRegistry(ctx)
  94. endpointRegistry := service.FromContext[adapter.EndpointRegistry](ctx)
  95. inboundRegistry := service.FromContext[adapter.InboundRegistry](ctx)
  96. outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
  97. dnsTransportRegistry := service.FromContext[adapter.DNSTransportRegistry](ctx)
  98. if endpointRegistry == nil {
  99. return nil, E.New("missing endpoint registry in context")
  100. }
  101. if inboundRegistry == nil {
  102. return nil, E.New("missing inbound registry in context")
  103. }
  104. if outboundRegistry == nil {
  105. return nil, E.New("missing outbound registry in context")
  106. }
  107. ctx = pause.WithDefaultManager(ctx)
  108. experimentalOptions := common.PtrValueOrDefault(options.Experimental)
  109. applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))
  110. var needCacheFile bool
  111. var needClashAPI bool
  112. var needV2RayAPI bool
  113. if experimentalOptions.CacheFile != nil && experimentalOptions.CacheFile.Enabled || options.PlatformLogWriter != nil {
  114. needCacheFile = true
  115. }
  116. if experimentalOptions.ClashAPI != nil || options.PlatformLogWriter != nil {
  117. needClashAPI = true
  118. }
  119. if experimentalOptions.V2RayAPI != nil && experimentalOptions.V2RayAPI.Listen != "" {
  120. needV2RayAPI = true
  121. }
  122. platformInterface := service.FromContext[platform.Interface](ctx)
  123. var defaultLogWriter io.Writer
  124. if platformInterface != nil {
  125. defaultLogWriter = io.Discard
  126. }
  127. logFactory, err := log.New(log.Options{
  128. Context: ctx,
  129. Options: common.PtrValueOrDefault(options.Log),
  130. Observable: needClashAPI,
  131. DefaultWriter: defaultLogWriter,
  132. BaseTime: createdAt,
  133. PlatformWriter: options.PlatformLogWriter,
  134. })
  135. if err != nil {
  136. return nil, E.Cause(err, "create log factory")
  137. }
  138. var services []adapter.LifecycleService
  139. certificateOptions := common.PtrValueOrDefault(options.Certificate)
  140. if C.IsAndroid || certificateOptions.Store != "" && certificateOptions.Store != C.CertificateStoreSystem ||
  141. len(certificateOptions.Certificate) > 0 ||
  142. len(certificateOptions.CertificatePath) > 0 ||
  143. len(certificateOptions.CertificateDirectoryPath) > 0 {
  144. certificateStore, err := certificate.NewStore(ctx, logFactory.NewLogger("certificate"), certificateOptions)
  145. if err != nil {
  146. return nil, err
  147. }
  148. service.MustRegister[adapter.CertificateStore](ctx, certificateStore)
  149. services = append(services, certificateStore)
  150. }
  151. routeOptions := common.PtrValueOrDefault(options.Route)
  152. dnsOptions := common.PtrValueOrDefault(options.DNS)
  153. endpointManager := endpoint.NewManager(logFactory.NewLogger("endpoint"), endpointRegistry)
  154. inboundManager := inbound.NewManager(logFactory.NewLogger("inbound"), inboundRegistry, endpointManager)
  155. outboundManager := outbound.NewManager(logFactory.NewLogger("outbound"), outboundRegistry, endpointManager, routeOptions.Final)
  156. dnsTransportManager := dns.NewTransportManager(logFactory.NewLogger("dns/transport"), dnsTransportRegistry, outboundManager, dnsOptions.Final)
  157. service.MustRegister[adapter.EndpointManager](ctx, endpointManager)
  158. service.MustRegister[adapter.InboundManager](ctx, inboundManager)
  159. service.MustRegister[adapter.OutboundManager](ctx, outboundManager)
  160. service.MustRegister[adapter.DNSTransportManager](ctx, dnsTransportManager)
  161. dnsRouter := dns.NewRouter(ctx, logFactory, dnsOptions)
  162. service.MustRegister[adapter.DNSRouter](ctx, dnsRouter)
  163. networkManager, err := route.NewNetworkManager(ctx, logFactory.NewLogger("network"), routeOptions)
  164. if err != nil {
  165. return nil, E.Cause(err, "initialize network manager")
  166. }
  167. service.MustRegister[adapter.NetworkManager](ctx, networkManager)
  168. connectionManager := route.NewConnectionManager(ctx, logFactory.NewLogger("connection"))
  169. service.MustRegister[adapter.ConnectionManager](ctx, connectionManager)
  170. router := route.NewRouter(ctx, logFactory, routeOptions, dnsOptions)
  171. service.MustRegister[adapter.Router](ctx, router)
  172. err = router.Initialize(routeOptions.Rules, routeOptions.RuleSet)
  173. if err != nil {
  174. return nil, E.Cause(err, "initialize router")
  175. }
  176. var timeService *tls.TimeServiceWrapper
  177. ntpOptions := common.PtrValueOrDefault(options.NTP)
  178. if ntpOptions.Enabled {
  179. timeService = new(tls.TimeServiceWrapper)
  180. service.MustRegister[ntp.TimeService](ctx, timeService)
  181. }
  182. for i, transportOptions := range dnsOptions.Servers {
  183. var tag string
  184. if transportOptions.Tag != "" {
  185. tag = transportOptions.Tag
  186. } else {
  187. tag = F.ToString(i)
  188. }
  189. err = dnsTransportManager.Create(
  190. ctx,
  191. logFactory.NewLogger(F.ToString("dns/", transportOptions.Type, "[", tag, "]")),
  192. tag,
  193. transportOptions.Type,
  194. transportOptions.Options,
  195. )
  196. if err != nil {
  197. return nil, E.Cause(err, "initialize DNS server[", i, "]")
  198. }
  199. }
  200. err = dnsRouter.Initialize(dnsOptions.Rules)
  201. if err != nil {
  202. return nil, E.Cause(err, "initialize dns router")
  203. }
  204. for i, endpointOptions := range options.Endpoints {
  205. var tag string
  206. if endpointOptions.Tag != "" {
  207. tag = endpointOptions.Tag
  208. } else {
  209. tag = F.ToString(i)
  210. }
  211. err = endpointManager.Create(
  212. ctx,
  213. router,
  214. logFactory.NewLogger(F.ToString("endpoint/", endpointOptions.Type, "[", tag, "]")),
  215. tag,
  216. endpointOptions.Type,
  217. endpointOptions.Options,
  218. )
  219. if err != nil {
  220. return nil, E.Cause(err, "initialize endpoint[", i, "]")
  221. }
  222. }
  223. for i, inboundOptions := range options.Inbounds {
  224. var tag string
  225. if inboundOptions.Tag != "" {
  226. tag = inboundOptions.Tag
  227. } else {
  228. tag = F.ToString(i)
  229. }
  230. err = inboundManager.Create(
  231. ctx,
  232. router,
  233. logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")),
  234. tag,
  235. inboundOptions.Type,
  236. inboundOptions.Options,
  237. )
  238. if err != nil {
  239. return nil, E.Cause(err, "initialize inbound[", i, "]")
  240. }
  241. }
  242. for i, outboundOptions := range options.Outbounds {
  243. var tag string
  244. if outboundOptions.Tag != "" {
  245. tag = outboundOptions.Tag
  246. } else {
  247. tag = F.ToString(i)
  248. }
  249. outboundCtx := ctx
  250. if tag != "" {
  251. // TODO: remove this
  252. outboundCtx = adapter.WithContext(outboundCtx, &adapter.InboundContext{
  253. Outbound: tag,
  254. })
  255. }
  256. err = outboundManager.Create(
  257. outboundCtx,
  258. router,
  259. logFactory.NewLogger(F.ToString("outbound/", outboundOptions.Type, "[", tag, "]")),
  260. tag,
  261. outboundOptions.Type,
  262. outboundOptions.Options,
  263. )
  264. if err != nil {
  265. return nil, E.Cause(err, "initialize outbound[", i, "]")
  266. }
  267. }
  268. outboundManager.Initialize(common.Must1(
  269. direct.NewOutbound(
  270. ctx,
  271. router,
  272. logFactory.NewLogger("outbound/direct"),
  273. "direct",
  274. option.DirectOutboundOptions{},
  275. ),
  276. ))
  277. dnsTransportManager.Initialize(common.Must1(
  278. local.NewTransport(
  279. ctx,
  280. logFactory.NewLogger("dns/local"),
  281. "local",
  282. option.LocalDNSServerOptions{},
  283. )))
  284. scriptManager, err := script.NewManager(ctx, logFactory, options.Scripts)
  285. if err != nil {
  286. return nil, E.Cause(err, "initialize script manager")
  287. }
  288. service.MustRegister[adapter.ScriptManager](ctx, scriptManager)
  289. if platformInterface != nil {
  290. err = platformInterface.Initialize(networkManager)
  291. if err != nil {
  292. return nil, E.Cause(err, "initialize platform interface")
  293. }
  294. }
  295. if needCacheFile {
  296. cacheFile := cachefile.New(ctx, common.PtrValueOrDefault(experimentalOptions.CacheFile))
  297. service.MustRegister[adapter.CacheFile](ctx, cacheFile)
  298. services = append(services, cacheFile)
  299. }
  300. if needClashAPI {
  301. clashAPIOptions := common.PtrValueOrDefault(experimentalOptions.ClashAPI)
  302. clashAPIOptions.ModeList = experimental.CalculateClashModeList(options.Options)
  303. clashServer, err := experimental.NewClashServer(ctx, logFactory.(log.ObservableFactory), clashAPIOptions)
  304. if err != nil {
  305. return nil, E.Cause(err, "create clash-server")
  306. }
  307. router.SetTracker(clashServer)
  308. service.MustRegister[adapter.ClashServer](ctx, clashServer)
  309. services = append(services, clashServer)
  310. }
  311. if needV2RayAPI {
  312. v2rayServer, err := experimental.NewV2RayServer(logFactory.NewLogger("v2ray-api"), common.PtrValueOrDefault(experimentalOptions.V2RayAPI))
  313. if err != nil {
  314. return nil, E.Cause(err, "create v2ray-server")
  315. }
  316. if v2rayServer.StatsService() != nil {
  317. router.SetTracker(v2rayServer.StatsService())
  318. services = append(services, v2rayServer)
  319. service.MustRegister[adapter.V2RayServer](ctx, v2rayServer)
  320. }
  321. }
  322. if ntpOptions.Enabled {
  323. ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions, ntpOptions.ServerIsDomain())
  324. if err != nil {
  325. return nil, E.Cause(err, "create NTP service")
  326. }
  327. ntpService := ntp.NewService(ntp.Options{
  328. Context: ctx,
  329. Dialer: ntpDialer,
  330. Logger: logFactory.NewLogger("ntp"),
  331. Server: ntpOptions.ServerOptions.Build(),
  332. Interval: time.Duration(ntpOptions.Interval),
  333. WriteToSystem: ntpOptions.WriteToSystem,
  334. })
  335. timeService.TimeService = ntpService
  336. services = append(services, adapter.NewLifecycleService(ntpService, "ntp service"))
  337. }
  338. mitmOptions := common.PtrValueOrDefault(options.MITM)
  339. var mitmEngine adapter.MITMEngine
  340. if mitmOptions.Enabled {
  341. engine, err := mitm.NewEngine(ctx, logFactory.NewLogger("mitm"), mitmOptions)
  342. if err != nil {
  343. return nil, E.Cause(err, "create MITM engine")
  344. }
  345. service.MustRegister[adapter.MITMEngine](ctx, engine)
  346. mitmEngine = engine
  347. }
  348. return &Box{
  349. network: networkManager,
  350. endpoint: endpointManager,
  351. inbound: inboundManager,
  352. outbound: outboundManager,
  353. dnsTransport: dnsTransportManager,
  354. dnsRouter: dnsRouter,
  355. connection: connectionManager,
  356. router: router,
  357. script: scriptManager,
  358. mitm: mitmEngine,
  359. createdAt: createdAt,
  360. logFactory: logFactory,
  361. logger: logFactory.Logger(),
  362. services: services,
  363. done: make(chan struct{}),
  364. }, nil
  365. }
  366. func (s *Box) PreStart() error {
  367. err := s.preStart()
  368. if err != nil {
  369. // TODO: remove catch error
  370. defer func() {
  371. v := recover()
  372. if v != nil {
  373. println(err.Error())
  374. debug.PrintStack()
  375. panic("panic on early close: " + fmt.Sprint(v))
  376. }
  377. }()
  378. s.Close()
  379. return err
  380. }
  381. s.logger.Info("sing-box pre-started (", F.Seconds(time.Since(s.createdAt).Seconds()), "s)")
  382. return nil
  383. }
  384. func (s *Box) Start() error {
  385. err := s.start()
  386. if err != nil {
  387. // TODO: remove catch error
  388. defer func() {
  389. v := recover()
  390. if v != nil {
  391. println(err.Error())
  392. debug.PrintStack()
  393. println("panic on early start: " + fmt.Sprint(v))
  394. }
  395. }()
  396. s.Close()
  397. return err
  398. }
  399. s.logger.Info("sing-box started (", F.Seconds(time.Since(s.createdAt).Seconds()), "s)")
  400. return nil
  401. }
  402. func (s *Box) preStart() error {
  403. monitor := taskmonitor.New(s.logger, C.StartTimeout)
  404. monitor.Start("start logger")
  405. err := s.logFactory.Start()
  406. monitor.Finish()
  407. if err != nil {
  408. return E.Cause(err, "start logger")
  409. }
  410. err = adapter.StartNamed(adapter.StartStateInitialize, s.services) // cache-file clash-api v2ray-api
  411. if err != nil {
  412. return err
  413. }
  414. err = adapter.Start(adapter.StartStateInitialize, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.script, s.mitm, s.outbound, s.inbound, s.endpoint)
  415. if err != nil {
  416. return err
  417. }
  418. err = adapter.Start(adapter.StartStateStart, s.outbound, s.dnsTransport, s.dnsRouter, s.network, s.connection, s.router, s.script, s.mitm)
  419. if err != nil {
  420. return err
  421. }
  422. return nil
  423. }
  424. func (s *Box) start() error {
  425. err := s.preStart()
  426. if err != nil {
  427. return err
  428. }
  429. err = adapter.StartNamed(adapter.StartStateStart, s.services)
  430. if err != nil {
  431. return err
  432. }
  433. err = s.inbound.Start(adapter.StartStateStart)
  434. if err != nil {
  435. return err
  436. }
  437. err = adapter.Start(adapter.StartStateStart, s.endpoint)
  438. if err != nil {
  439. return err
  440. }
  441. err = adapter.Start(adapter.StartStatePostStart, s.outbound, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.script, s.mitm, s.inbound, s.endpoint)
  442. if err != nil {
  443. return err
  444. }
  445. err = adapter.StartNamed(adapter.StartStatePostStart, s.services)
  446. if err != nil {
  447. return err
  448. }
  449. err = adapter.Start(adapter.StartStateStarted, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.script, s.mitm, s.outbound, s.inbound, s.endpoint)
  450. if err != nil {
  451. return err
  452. }
  453. err = adapter.StartNamed(adapter.StartStateStarted, s.services)
  454. if err != nil {
  455. return err
  456. }
  457. return nil
  458. }
  459. func (s *Box) Close() error {
  460. select {
  461. case <-s.done:
  462. return os.ErrClosed
  463. default:
  464. close(s.done)
  465. }
  466. err := common.Close(
  467. s.inbound, s.outbound, s.endpoint, s.mitm, s.script, s.router, s.connection, s.dnsRouter, s.dnsTransport, s.network,
  468. )
  469. for _, lifecycleService := range s.services {
  470. err = E.Append(err, lifecycleService.Close(), func(err error) error {
  471. return E.Cause(err, "close ", lifecycleService.Name())
  472. })
  473. }
  474. err = E.Append(err, s.logFactory.Close(), func(err error) error {
  475. return E.Cause(err, "close logger")
  476. })
  477. return err
  478. }
  479. func (s *Box) Network() adapter.NetworkManager {
  480. return s.network
  481. }
  482. func (s *Box) Router() adapter.Router {
  483. return s.router
  484. }
  485. func (s *Box) Inbound() adapter.InboundManager {
  486. return s.inbound
  487. }
  488. func (s *Box) Outbound() adapter.OutboundManager {
  489. return s.outbound
  490. }