box.go 17 KB

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