box.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  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. C "github.com/sagernet/sing-box/constant"
  11. "github.com/sagernet/sing-box/experimental"
  12. "github.com/sagernet/sing-box/experimental/libbox/platform"
  13. "github.com/sagernet/sing-box/inbound"
  14. "github.com/sagernet/sing-box/log"
  15. "github.com/sagernet/sing-box/option"
  16. "github.com/sagernet/sing-box/outbound"
  17. "github.com/sagernet/sing-box/route"
  18. "github.com/sagernet/sing/common"
  19. E "github.com/sagernet/sing/common/exceptions"
  20. F "github.com/sagernet/sing/common/format"
  21. )
  22. var _ adapter.Service = (*Box)(nil)
  23. type Box struct {
  24. createdAt time.Time
  25. router adapter.Router
  26. inbounds []adapter.Inbound
  27. outbounds []adapter.Outbound
  28. logFactory log.Factory
  29. logger log.ContextLogger
  30. logFile *os.File
  31. preServices map[string]adapter.Service
  32. postServices map[string]adapter.Service
  33. done chan struct{}
  34. }
  35. func New(ctx context.Context, options option.Options, platformInterface platform.Interface) (*Box, error) {
  36. createdAt := time.Now()
  37. experimentalOptions := common.PtrValueOrDefault(options.Experimental)
  38. applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))
  39. var needClashAPI bool
  40. var needV2RayAPI bool
  41. if experimentalOptions.ClashAPI != nil && experimentalOptions.ClashAPI.ExternalController != "" {
  42. needClashAPI = true
  43. }
  44. if experimentalOptions.V2RayAPI != nil && experimentalOptions.V2RayAPI.Listen != "" {
  45. needV2RayAPI = true
  46. }
  47. logOptions := common.PtrValueOrDefault(options.Log)
  48. var logFactory log.Factory
  49. var observableLogFactory log.ObservableFactory
  50. var logFile *os.File
  51. var logWriter io.Writer
  52. if logOptions.Disabled {
  53. observableLogFactory = log.NewNOPFactory()
  54. logFactory = observableLogFactory
  55. } else {
  56. switch logOptions.Output {
  57. case "":
  58. if platformInterface != nil {
  59. logWriter = io.Discard
  60. } else {
  61. logWriter = os.Stdout
  62. }
  63. case "stderr":
  64. logWriter = os.Stderr
  65. case "stdout":
  66. logWriter = os.Stdout
  67. default:
  68. var err error
  69. logFile, err = os.OpenFile(C.BasePath(logOptions.Output), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
  70. if err != nil {
  71. return nil, err
  72. }
  73. logWriter = logFile
  74. }
  75. logFormatter := log.Formatter{
  76. BaseTime: createdAt,
  77. DisableColors: logOptions.DisableColor || logFile != nil,
  78. DisableTimestamp: !logOptions.Timestamp && logFile != nil,
  79. FullTimestamp: logOptions.Timestamp,
  80. TimestampFormat: "-0700 2006-01-02 15:04:05",
  81. }
  82. if needClashAPI {
  83. observableLogFactory = log.NewObservableFactory(logFormatter, logWriter, platformInterface)
  84. logFactory = observableLogFactory
  85. } else {
  86. logFactory = log.NewFactory(logFormatter, logWriter, platformInterface)
  87. }
  88. if logOptions.Level != "" {
  89. logLevel, err := log.ParseLevel(logOptions.Level)
  90. if err != nil {
  91. return nil, E.Cause(err, "parse log level")
  92. }
  93. logFactory.SetLevel(logLevel)
  94. } else {
  95. logFactory.SetLevel(log.LevelTrace)
  96. }
  97. }
  98. router, err := route.NewRouter(
  99. ctx,
  100. logFactory,
  101. common.PtrValueOrDefault(options.Route),
  102. common.PtrValueOrDefault(options.DNS),
  103. common.PtrValueOrDefault(options.NTP),
  104. options.Inbounds,
  105. platformInterface,
  106. )
  107. if err != nil {
  108. return nil, E.Cause(err, "parse route options")
  109. }
  110. inbounds := make([]adapter.Inbound, 0, len(options.Inbounds))
  111. outbounds := make([]adapter.Outbound, 0, len(options.Outbounds))
  112. for i, inboundOptions := range options.Inbounds {
  113. var in adapter.Inbound
  114. var tag string
  115. if inboundOptions.Tag != "" {
  116. tag = inboundOptions.Tag
  117. } else {
  118. tag = F.ToString(i)
  119. }
  120. in, err = inbound.New(
  121. ctx,
  122. router,
  123. logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")),
  124. inboundOptions,
  125. platformInterface,
  126. )
  127. if err != nil {
  128. return nil, E.Cause(err, "parse inbound[", i, "]")
  129. }
  130. inbounds = append(inbounds, in)
  131. }
  132. for i, outboundOptions := range options.Outbounds {
  133. var out adapter.Outbound
  134. var tag string
  135. if outboundOptions.Tag != "" {
  136. tag = outboundOptions.Tag
  137. } else {
  138. tag = F.ToString(i)
  139. }
  140. out, err = outbound.New(
  141. ctx,
  142. router,
  143. logFactory.NewLogger(F.ToString("outbound/", outboundOptions.Type, "[", tag, "]")),
  144. outboundOptions)
  145. if err != nil {
  146. return nil, E.Cause(err, "parse outbound[", i, "]")
  147. }
  148. outbounds = append(outbounds, out)
  149. }
  150. err = router.Initialize(inbounds, outbounds, func() adapter.Outbound {
  151. out, oErr := outbound.New(ctx, router, logFactory.NewLogger("outbound/direct"), option.Outbound{Type: "direct", Tag: "default"})
  152. common.Must(oErr)
  153. outbounds = append(outbounds, out)
  154. return out
  155. })
  156. if err != nil {
  157. return nil, err
  158. }
  159. preServices := make(map[string]adapter.Service)
  160. postServices := make(map[string]adapter.Service)
  161. if needClashAPI {
  162. clashServer, err := experimental.NewClashServer(router, observableLogFactory, common.PtrValueOrDefault(options.Experimental.ClashAPI))
  163. if err != nil {
  164. return nil, E.Cause(err, "create clash api server")
  165. }
  166. router.SetClashServer(clashServer)
  167. preServices["clash api"] = clashServer
  168. }
  169. if needV2RayAPI {
  170. v2rayServer, err := experimental.NewV2RayServer(logFactory.NewLogger("v2ray-api"), common.PtrValueOrDefault(options.Experimental.V2RayAPI))
  171. if err != nil {
  172. return nil, E.Cause(err, "create v2ray api server")
  173. }
  174. router.SetV2RayServer(v2rayServer)
  175. preServices["v2ray api"] = v2rayServer
  176. }
  177. return &Box{
  178. router: router,
  179. inbounds: inbounds,
  180. outbounds: outbounds,
  181. createdAt: createdAt,
  182. logFactory: logFactory,
  183. logger: logFactory.Logger(),
  184. logFile: logFile,
  185. preServices: preServices,
  186. postServices: postServices,
  187. done: make(chan struct{}),
  188. }, nil
  189. }
  190. func (s *Box) PreStart() error {
  191. err := s.preStart()
  192. if err != nil {
  193. // TODO: remove catch error
  194. defer func() {
  195. v := recover()
  196. if v != nil {
  197. log.Error(E.Cause(err, "origin error"))
  198. debug.PrintStack()
  199. panic("panic on early close: " + fmt.Sprint(v))
  200. }
  201. }()
  202. s.Close()
  203. return err
  204. }
  205. s.logger.Info("sing-box pre-started (", F.Seconds(time.Since(s.createdAt).Seconds()), "s)")
  206. return nil
  207. }
  208. func (s *Box) Start() error {
  209. err := s.start()
  210. if err != nil {
  211. // TODO: remove catch error
  212. defer func() {
  213. v := recover()
  214. if v != nil {
  215. log.Error(E.Cause(err, "origin error"))
  216. debug.PrintStack()
  217. panic("panic on early close: " + fmt.Sprint(v))
  218. }
  219. }()
  220. s.Close()
  221. return err
  222. }
  223. s.logger.Info("sing-box started (", F.Seconds(time.Since(s.createdAt).Seconds()), "s)")
  224. return nil
  225. }
  226. func (s *Box) preStart() error {
  227. for serviceName, service := range s.preServices {
  228. s.logger.Trace("pre-starting ", serviceName)
  229. err := adapter.PreStart(service)
  230. if err != nil {
  231. return E.Cause(err, "pre-start ", serviceName)
  232. }
  233. }
  234. for i, out := range s.outbounds {
  235. if starter, isStarter := out.(common.Starter); isStarter {
  236. var tag string
  237. if out.Tag() == "" {
  238. tag = F.ToString(i)
  239. } else {
  240. tag = out.Tag()
  241. }
  242. s.logger.Trace("initializing outbound ", tag)
  243. err := starter.Start()
  244. if err != nil {
  245. return E.Cause(err, "initialize outbound/", out.Type(), "[", tag, "]")
  246. }
  247. }
  248. }
  249. return s.router.Start()
  250. }
  251. func (s *Box) start() error {
  252. err := s.preStart()
  253. if err != nil {
  254. return err
  255. }
  256. for serviceName, service := range s.preServices {
  257. s.logger.Trace("starting ", serviceName)
  258. err = service.Start()
  259. if err != nil {
  260. return E.Cause(err, "start ", serviceName)
  261. }
  262. }
  263. for i, in := range s.inbounds {
  264. var tag string
  265. if in.Tag() == "" {
  266. tag = F.ToString(i)
  267. } else {
  268. tag = in.Tag()
  269. }
  270. s.logger.Trace("initializing inbound ", tag)
  271. err = in.Start()
  272. if err != nil {
  273. return E.Cause(err, "initialize inbound/", in.Type(), "[", tag, "]")
  274. }
  275. }
  276. for serviceName, service := range s.postServices {
  277. s.logger.Trace("start ", serviceName)
  278. err = service.Start()
  279. if err != nil {
  280. return E.Cause(err, "starting ", serviceName)
  281. }
  282. }
  283. return nil
  284. }
  285. func (s *Box) Close() error {
  286. select {
  287. case <-s.done:
  288. return os.ErrClosed
  289. default:
  290. close(s.done)
  291. }
  292. var errors error
  293. for serviceName, service := range s.postServices {
  294. errors = E.Append(errors, service.Close(), func(err error) error {
  295. s.logger.Trace("closing ", serviceName)
  296. return E.Cause(err, "close ", serviceName)
  297. })
  298. }
  299. for i, in := range s.inbounds {
  300. var tag string
  301. if in.Tag() == "" {
  302. tag = F.ToString(i)
  303. } else {
  304. tag = in.Tag()
  305. }
  306. s.logger.Trace("closing inbound ", tag)
  307. errors = E.Append(errors, in.Close(), func(err error) error {
  308. return E.Cause(err, "close inbound/", in.Type(), "[", i, "]")
  309. })
  310. }
  311. for i, out := range s.outbounds {
  312. var tag string
  313. if out.Tag() == "" {
  314. tag = F.ToString(i)
  315. } else {
  316. tag = out.Tag()
  317. }
  318. s.logger.Trace("closing outbound ", tag)
  319. errors = E.Append(errors, common.Close(out), func(err error) error {
  320. return E.Cause(err, "close inbound/", out.Type(), "[", i, "]")
  321. })
  322. }
  323. s.logger.Trace("closing router")
  324. if err := common.Close(s.router); err != nil {
  325. errors = E.Append(errors, err, func(err error) error {
  326. return E.Cause(err, "close router")
  327. })
  328. }
  329. for serviceName, service := range s.preServices {
  330. s.logger.Trace("closing ", serviceName)
  331. errors = E.Append(errors, service.Close(), func(err error) error {
  332. return E.Cause(err, "close ", serviceName)
  333. })
  334. }
  335. s.logger.Trace("closing logger")
  336. if err := common.Close(s.logFactory); err != nil {
  337. errors = E.Append(errors, err, func(err error) error {
  338. return E.Cause(err, "close log factory")
  339. })
  340. }
  341. if s.logFile != nil {
  342. errors = E.Append(errors, s.logFile.Close(), func(err error) error {
  343. return E.Cause(err, "close log file")
  344. })
  345. }
  346. return errors
  347. }
  348. func (s *Box) Router() adapter.Router {
  349. return s.router
  350. }