box.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  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. certificateStore, err := certificate.NewStore(ctx, logFactory.NewLogger("certificate"), common.PtrValueOrDefault(options.Certificate))
  140. if err != nil {
  141. return nil, err
  142. }
  143. service.MustRegister[adapter.CertificateStore](ctx, certificateStore)
  144. services = append(services, certificateStore)
  145. routeOptions := common.PtrValueOrDefault(options.Route)
  146. dnsOptions := common.PtrValueOrDefault(options.DNS)
  147. endpointManager := endpoint.NewManager(logFactory.NewLogger("endpoint"), endpointRegistry)
  148. inboundManager := inbound.NewManager(logFactory.NewLogger("inbound"), inboundRegistry, endpointManager)
  149. outboundManager := outbound.NewManager(logFactory.NewLogger("outbound"), outboundRegistry, endpointManager, routeOptions.Final)
  150. dnsTransportManager := dns.NewTransportManager(logFactory.NewLogger("dns/transport"), dnsTransportRegistry, outboundManager, dnsOptions.Final)
  151. service.MustRegister[adapter.EndpointManager](ctx, endpointManager)
  152. service.MustRegister[adapter.InboundManager](ctx, inboundManager)
  153. service.MustRegister[adapter.OutboundManager](ctx, outboundManager)
  154. service.MustRegister[adapter.DNSTransportManager](ctx, dnsTransportManager)
  155. dnsRouter := dns.NewRouter(ctx, logFactory, dnsOptions)
  156. service.MustRegister[adapter.DNSRouter](ctx, dnsRouter)
  157. networkManager, err := route.NewNetworkManager(ctx, logFactory.NewLogger("network"), routeOptions)
  158. if err != nil {
  159. return nil, E.Cause(err, "initialize network manager")
  160. }
  161. service.MustRegister[adapter.NetworkManager](ctx, networkManager)
  162. connectionManager := route.NewConnectionManager(ctx, logFactory.NewLogger("connection"))
  163. service.MustRegister[adapter.ConnectionManager](ctx, connectionManager)
  164. router := route.NewRouter(ctx, logFactory, routeOptions, dnsOptions)
  165. service.MustRegister[adapter.Router](ctx, router)
  166. err = router.Initialize(routeOptions.Rules, routeOptions.RuleSet)
  167. if err != nil {
  168. return nil, E.Cause(err, "initialize router")
  169. }
  170. var timeService *tls.TimeServiceWrapper
  171. ntpOptions := common.PtrValueOrDefault(options.NTP)
  172. if ntpOptions.Enabled {
  173. timeService = new(tls.TimeServiceWrapper)
  174. service.MustRegister[ntp.TimeService](ctx, timeService)
  175. }
  176. for i, transportOptions := range dnsOptions.Servers {
  177. var tag string
  178. if transportOptions.Tag != "" {
  179. tag = transportOptions.Tag
  180. } else {
  181. tag = F.ToString(i)
  182. }
  183. err = dnsTransportManager.Create(
  184. ctx,
  185. logFactory.NewLogger(F.ToString("dns/", transportOptions.Type, "[", tag, "]")),
  186. tag,
  187. transportOptions.Type,
  188. transportOptions.Options,
  189. )
  190. if err != nil {
  191. return nil, E.Cause(err, "initialize DNS server[", i, "]")
  192. }
  193. }
  194. err = dnsRouter.Initialize(dnsOptions.Rules)
  195. if err != nil {
  196. return nil, E.Cause(err, "initialize dns router")
  197. }
  198. for i, endpointOptions := range options.Endpoints {
  199. var tag string
  200. if endpointOptions.Tag != "" {
  201. tag = endpointOptions.Tag
  202. } else {
  203. tag = F.ToString(i)
  204. }
  205. endpointCtx := ctx
  206. if tag != "" {
  207. // TODO: remove this
  208. endpointCtx = adapter.WithContext(endpointCtx, &adapter.InboundContext{
  209. Outbound: tag,
  210. })
  211. }
  212. err = endpointManager.Create(
  213. endpointCtx,
  214. router,
  215. logFactory.NewLogger(F.ToString("endpoint/", endpointOptions.Type, "[", tag, "]")),
  216. tag,
  217. endpointOptions.Type,
  218. endpointOptions.Options,
  219. )
  220. if err != nil {
  221. return nil, E.Cause(err, "initialize endpoint[", i, "]")
  222. }
  223. }
  224. for i, inboundOptions := range options.Inbounds {
  225. var tag string
  226. if inboundOptions.Tag != "" {
  227. tag = inboundOptions.Tag
  228. } else {
  229. tag = F.ToString(i)
  230. }
  231. err = inboundManager.Create(
  232. ctx,
  233. router,
  234. logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")),
  235. tag,
  236. inboundOptions.Type,
  237. inboundOptions.Options,
  238. )
  239. if err != nil {
  240. return nil, E.Cause(err, "initialize inbound[", i, "]")
  241. }
  242. }
  243. for i, outboundOptions := range options.Outbounds {
  244. var tag string
  245. if outboundOptions.Tag != "" {
  246. tag = outboundOptions.Tag
  247. } else {
  248. tag = F.ToString(i)
  249. }
  250. outboundCtx := ctx
  251. if tag != "" {
  252. // TODO: remove this
  253. outboundCtx = adapter.WithContext(outboundCtx, &adapter.InboundContext{
  254. Outbound: tag,
  255. })
  256. }
  257. err = outboundManager.Create(
  258. outboundCtx,
  259. router,
  260. logFactory.NewLogger(F.ToString("outbound/", outboundOptions.Type, "[", tag, "]")),
  261. tag,
  262. outboundOptions.Type,
  263. outboundOptions.Options,
  264. )
  265. if err != nil {
  266. return nil, E.Cause(err, "initialize outbound[", i, "]")
  267. }
  268. }
  269. outboundManager.Initialize(common.Must1(
  270. direct.NewOutbound(
  271. ctx,
  272. router,
  273. logFactory.NewLogger("outbound/direct"),
  274. "direct",
  275. option.DirectOutboundOptions{},
  276. ),
  277. ))
  278. dnsTransportManager.Initialize(common.Must1(
  279. local.NewTransport(
  280. ctx,
  281. logFactory.NewLogger("dns/local"),
  282. "local",
  283. option.LocalDNSServerOptions{},
  284. )))
  285. scriptManager, err := script.NewManager(ctx, logFactory, options.Scripts)
  286. if err != nil {
  287. return nil, E.Cause(err, "initialize script manager")
  288. }
  289. service.MustRegister[adapter.ScriptManager](ctx, scriptManager)
  290. if platformInterface != nil {
  291. err = platformInterface.Initialize(networkManager)
  292. if err != nil {
  293. return nil, E.Cause(err, "initialize platform interface")
  294. }
  295. }
  296. if needCacheFile {
  297. cacheFile := cachefile.New(ctx, common.PtrValueOrDefault(experimentalOptions.CacheFile))
  298. service.MustRegister[adapter.CacheFile](ctx, cacheFile)
  299. services = append(services, cacheFile)
  300. }
  301. if needClashAPI {
  302. clashAPIOptions := common.PtrValueOrDefault(experimentalOptions.ClashAPI)
  303. clashAPIOptions.ModeList = experimental.CalculateClashModeList(options.Options)
  304. clashServer, err := experimental.NewClashServer(ctx, logFactory.(log.ObservableFactory), clashAPIOptions)
  305. if err != nil {
  306. return nil, E.Cause(err, "create clash-server")
  307. }
  308. router.SetTracker(clashServer)
  309. service.MustRegister[adapter.ClashServer](ctx, clashServer)
  310. services = append(services, clashServer)
  311. }
  312. if needV2RayAPI {
  313. v2rayServer, err := experimental.NewV2RayServer(logFactory.NewLogger("v2ray-api"), common.PtrValueOrDefault(experimentalOptions.V2RayAPI))
  314. if err != nil {
  315. return nil, E.Cause(err, "create v2ray-server")
  316. }
  317. if v2rayServer.StatsService() != nil {
  318. router.SetTracker(v2rayServer.StatsService())
  319. services = append(services, v2rayServer)
  320. service.MustRegister[adapter.V2RayServer](ctx, v2rayServer)
  321. }
  322. }
  323. if ntpOptions.Enabled {
  324. ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions, ntpOptions.ServerIsDomain())
  325. if err != nil {
  326. return nil, E.Cause(err, "create NTP service")
  327. }
  328. ntpService := ntp.NewService(ntp.Options{
  329. Context: ctx,
  330. Dialer: ntpDialer,
  331. Logger: logFactory.NewLogger("ntp"),
  332. Server: ntpOptions.ServerOptions.Build(),
  333. Interval: time.Duration(ntpOptions.Interval),
  334. WriteToSystem: ntpOptions.WriteToSystem,
  335. })
  336. timeService.TimeService = ntpService
  337. services = append(services, adapter.NewLifecycleService(ntpService, "ntp service"))
  338. }
  339. mitmOptions := common.PtrValueOrDefault(options.MITM)
  340. var mitmEngine adapter.MITMEngine
  341. if mitmOptions.Enabled {
  342. engine, err := mitm.NewEngine(ctx, logFactory.NewLogger("mitm"), mitmOptions)
  343. if err != nil {
  344. return nil, E.Cause(err, "create MITM engine")
  345. }
  346. service.MustRegister[adapter.MITMEngine](ctx, engine)
  347. mitmEngine = engine
  348. }
  349. return &Box{
  350. network: networkManager,
  351. endpoint: endpointManager,
  352. inbound: inboundManager,
  353. outbound: outboundManager,
  354. dnsTransport: dnsTransportManager,
  355. dnsRouter: dnsRouter,
  356. connection: connectionManager,
  357. router: router,
  358. script: scriptManager,
  359. mitm: mitmEngine,
  360. createdAt: createdAt,
  361. logFactory: logFactory,
  362. logger: logFactory.Logger(),
  363. services: services,
  364. done: make(chan struct{}),
  365. }, nil
  366. }
  367. func (s *Box) PreStart() error {
  368. err := s.preStart()
  369. if err != nil {
  370. // TODO: remove catch error
  371. defer func() {
  372. v := recover()
  373. if v != nil {
  374. println(err.Error())
  375. debug.PrintStack()
  376. panic("panic on early close: " + fmt.Sprint(v))
  377. }
  378. }()
  379. s.Close()
  380. return err
  381. }
  382. s.logger.Info("sing-box pre-started (", F.Seconds(time.Since(s.createdAt).Seconds()), "s)")
  383. return nil
  384. }
  385. func (s *Box) Start() error {
  386. err := s.start()
  387. if err != nil {
  388. // TODO: remove catch error
  389. defer func() {
  390. v := recover()
  391. if v != nil {
  392. println(err.Error())
  393. debug.PrintStack()
  394. println("panic on early start: " + fmt.Sprint(v))
  395. }
  396. }()
  397. s.Close()
  398. return err
  399. }
  400. s.logger.Info("sing-box started (", F.Seconds(time.Since(s.createdAt).Seconds()), "s)")
  401. return nil
  402. }
  403. func (s *Box) preStart() error {
  404. monitor := taskmonitor.New(s.logger, C.StartTimeout)
  405. monitor.Start("start logger")
  406. err := s.logFactory.Start()
  407. monitor.Finish()
  408. if err != nil {
  409. return E.Cause(err, "start logger")
  410. }
  411. err = adapter.StartNamed(adapter.StartStateInitialize, s.services) // cache-file clash-api v2ray-api
  412. if err != nil {
  413. return err
  414. }
  415. 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)
  416. if err != nil {
  417. return err
  418. }
  419. err = adapter.Start(adapter.StartStateStart, s.outbound, s.dnsTransport, s.dnsRouter, s.network, s.connection, s.router, s.script, s.mitm)
  420. if err != nil {
  421. return err
  422. }
  423. return nil
  424. }
  425. func (s *Box) start() error {
  426. err := s.preStart()
  427. if err != nil {
  428. return err
  429. }
  430. err = adapter.StartNamed(adapter.StartStateStart, s.services)
  431. if err != nil {
  432. return err
  433. }
  434. err = s.inbound.Start(adapter.StartStateStart)
  435. if err != nil {
  436. return err
  437. }
  438. err = adapter.Start(adapter.StartStateStart, s.endpoint)
  439. if err != nil {
  440. return err
  441. }
  442. 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)
  443. if err != nil {
  444. return err
  445. }
  446. err = adapter.StartNamed(adapter.StartStatePostStart, s.services)
  447. if err != nil {
  448. return err
  449. }
  450. 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)
  451. if err != nil {
  452. return err
  453. }
  454. err = adapter.StartNamed(adapter.StartStateStarted, s.services)
  455. if err != nil {
  456. return err
  457. }
  458. return nil
  459. }
  460. func (s *Box) Close() error {
  461. select {
  462. case <-s.done:
  463. return os.ErrClosed
  464. default:
  465. close(s.done)
  466. }
  467. err := common.Close(
  468. s.inbound, s.outbound, s.endpoint, s.mitm, s.script, s.router, s.connection, s.dnsRouter, s.dnsTransport, s.network,
  469. )
  470. for _, lifecycleService := range s.services {
  471. err = E.Append(err, lifecycleService.Close(), func(err error) error {
  472. return E.Cause(err, "close ", lifecycleService.Name())
  473. })
  474. }
  475. err = E.Append(err, s.logFactory.Close(), func(err error) error {
  476. return E.Cause(err, "close logger")
  477. })
  478. return err
  479. }
  480. func (s *Box) Network() adapter.NetworkManager {
  481. return s.network
  482. }
  483. func (s *Box) Router() adapter.Router {
  484. return s.router
  485. }
  486. func (s *Box) Inbound() adapter.InboundManager {
  487. return s.inbound
  488. }
  489. func (s *Box) Outbound() adapter.OutboundManager {
  490. return s.outbound
  491. }