box.go 15 KB

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