nps.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package main
  2. import (
  3. "ehang.io/nps/lib/install"
  4. "flag"
  5. "log"
  6. "os"
  7. "path/filepath"
  8. "runtime"
  9. "strings"
  10. "ehang.io/nps/lib/common"
  11. "ehang.io/nps/lib/crypt"
  12. "ehang.io/nps/lib/daemon"
  13. "ehang.io/nps/lib/file"
  14. "ehang.io/nps/lib/version"
  15. "ehang.io/nps/server"
  16. "ehang.io/nps/server/connection"
  17. "ehang.io/nps/server/tool"
  18. "github.com/astaxie/beego"
  19. "github.com/astaxie/beego/logs"
  20. "ehang.io/nps/web/routers"
  21. "github.com/kardianos/service"
  22. )
  23. var (
  24. level string
  25. )
  26. const systemdScript = `[Unit]
  27. Description={{.Description}}
  28. ConditionFileIsExecutable={{.Path|cmdEscape}}
  29. {{range $i, $dep := .Dependencies}}
  30. {{$dep}} {{end}}
  31. [Service]
  32. LimitNOFILE=65536
  33. StartLimitInterval=5
  34. StartLimitBurst=10
  35. ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}}
  36. {{if .ChRoot}}RootDirectory={{.ChRoot|cmd}}{{end}}
  37. {{if .WorkingDirectory}}WorkingDirectory={{.WorkingDirectory|cmdEscape}}{{end}}
  38. {{if .UserName}}User={{.UserName}}{{end}}
  39. {{if .ReloadSignal}}ExecReload=/bin/kill -{{.ReloadSignal}} "$MAINPID"{{end}}
  40. {{if .PIDFile}}PIDFile={{.PIDFile|cmd}}{{end}}
  41. {{if and .LogOutput .HasOutputFileSupport -}}
  42. StandardOutput=file:/var/log/{{.Name}}.out
  43. StandardError=file:/var/log/{{.Name}}.err
  44. {{- end}}
  45. Restart=always
  46. RestartSec=120
  47. [Install]
  48. WantedBy=multi-user.target
  49. `
  50. func main() {
  51. flag.Parse()
  52. // init log
  53. if err := beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "nps.conf")); err != nil {
  54. log.Fatalln("load config file error", err.Error())
  55. }
  56. if level = beego.AppConfig.String("log_level"); level == "" {
  57. level = "7"
  58. }
  59. logs.Reset()
  60. logs.EnableFuncCallDepth(true)
  61. logs.SetLogFuncCallDepth(3)
  62. logPath := beego.AppConfig.String("log_path")
  63. if logPath == "" {
  64. logPath = common.GetLogPath()
  65. }
  66. if common.IsWindows() {
  67. logPath = strings.Replace(logPath, "\\", "\\\\", -1)
  68. }
  69. // init service
  70. options := make(service.KeyValue)
  71. svcConfig := &service.Config{
  72. Name: "Nps",
  73. DisplayName: "nps内网穿透代理服务器",
  74. Description: "一款轻量级、功能强大的内网穿透代理服务器。支持tcp、udp流量转发,支持内网http代理、内网socks5代理,同时支持snappy压缩、站点保护、加密传输、多路复用、header修改等。支持web图形化管理,集成多用户模式。",
  75. Option: options,
  76. }
  77. svcConfig.Arguments = append(svcConfig.Arguments, "service")
  78. if len(os.Args) > 1 && os.Args[1] == "service" {
  79. _ = logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+logPath+`","daily":false,"maxlines":100000,"color":true}`)
  80. } else {
  81. _ = logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
  82. }
  83. if !common.IsWindows() {
  84. svcConfig.Dependencies = []string{
  85. "Requires=network.target",
  86. "After=network-online.target syslog.target"}
  87. svcConfig.Option["SystemdScript"] = systemdScript
  88. }
  89. prg := &nps{}
  90. prg.exit = make(chan struct{})
  91. s, err := service.New(prg, svcConfig)
  92. if err != nil {
  93. logs.Error(err)
  94. return
  95. }
  96. if len(os.Args) > 1 && os.Args[1] != "service" {
  97. switch os.Args[1] {
  98. case "reload":
  99. daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath())
  100. return
  101. case "install":
  102. // uninstall before
  103. _ = service.Control(s, "stop")
  104. _ = service.Control(s, "uninstall")
  105. binPath := install.InstallNps()
  106. svcConfig.Executable = binPath
  107. s, err := service.New(prg, svcConfig)
  108. if err != nil {
  109. logs.Error(err)
  110. return
  111. }
  112. err = service.Control(s, os.Args[1])
  113. if err != nil {
  114. logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
  115. }
  116. return
  117. case "start", "restart", "stop", "uninstall":
  118. err := service.Control(s, os.Args[1])
  119. if err != nil {
  120. logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
  121. }
  122. return
  123. case "update":
  124. install.UpdateNps()
  125. return
  126. default:
  127. logs.Error("command is not support")
  128. return
  129. }
  130. }
  131. _ = s.Run()
  132. }
  133. type nps struct {
  134. exit chan struct{}
  135. }
  136. func (p *nps) Start(s service.Service) error {
  137. _, _ = s.Status()
  138. _ = p.run()
  139. return nil
  140. }
  141. func (p *nps) Stop(s service.Service) error {
  142. _, _ = s.Status()
  143. close(p.exit)
  144. if service.Interactive() {
  145. os.Exit(0)
  146. }
  147. return nil
  148. }
  149. func (p *nps) run() error {
  150. defer func() {
  151. if err := recover(); err != nil {
  152. const size = 64 << 10
  153. buf := make([]byte, size)
  154. buf = buf[:runtime.Stack(buf, false)]
  155. logs.Warning("nps: panic serving %v: %v\n%s", err, string(buf))
  156. }
  157. }()
  158. routers.Init()
  159. task := &file.Tunnel{
  160. Mode: "webServer",
  161. }
  162. bridgePort, err := beego.AppConfig.Int("bridge_port")
  163. if err != nil {
  164. logs.Error("Getting bridge_port error", err)
  165. os.Exit(0)
  166. }
  167. logs.Info("the version of server is %s ,allow client core version to be %s", version.VERSION, version.GetVersion())
  168. connection.InitConnectionService()
  169. crypt.InitTls(filepath.Join(common.GetRunPath(), "conf", "server.pem"), filepath.Join(common.GetRunPath(), "conf", "server.key"))
  170. tool.InitAllowPort()
  171. tool.StartSystemInfo()
  172. go server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"))
  173. select {
  174. case <-p.exit:
  175. logs.Warning("stop...")
  176. }
  177. return nil
  178. }