nps.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. common.InitPProfFromFile()
  57. if level = beego.AppConfig.String("log_level"); level == "" {
  58. level = "7"
  59. }
  60. logs.Reset()
  61. logs.EnableFuncCallDepth(true)
  62. logs.SetLogFuncCallDepth(3)
  63. logPath := beego.AppConfig.String("log_path")
  64. if logPath == "" {
  65. logPath = common.GetLogPath()
  66. }
  67. if common.IsWindows() {
  68. logPath = strings.Replace(logPath, "\\", "\\\\", -1)
  69. }
  70. // init service
  71. options := make(service.KeyValue)
  72. svcConfig := &service.Config{
  73. Name: "Nps",
  74. DisplayName: "nps内网穿透代理服务器",
  75. Description: "一款轻量级、功能强大的内网穿透代理服务器。支持tcp、udp流量转发,支持内网http代理、内网socks5代理,同时支持snappy压缩、站点保护、加密传输、多路复用、header修改等。支持web图形化管理,集成多用户模式。",
  76. Option: options,
  77. }
  78. svcConfig.Arguments = append(svcConfig.Arguments, "service")
  79. if len(os.Args) > 1 && os.Args[1] == "service" {
  80. _ = logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+logPath+`","daily":false,"maxlines":100000,"color":true}`)
  81. } else {
  82. _ = logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
  83. }
  84. if !common.IsWindows() {
  85. svcConfig.Dependencies = []string{
  86. "Requires=network.target",
  87. "After=network-online.target syslog.target"}
  88. svcConfig.Option["SystemdScript"] = systemdScript
  89. }
  90. prg := &nps{}
  91. prg.exit = make(chan struct{})
  92. s, err := service.New(prg, svcConfig)
  93. if err != nil {
  94. logs.Error(err)
  95. return
  96. }
  97. if len(os.Args) > 1 && os.Args[1] != "service" {
  98. switch os.Args[1] {
  99. case "reload":
  100. daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath())
  101. return
  102. case "install":
  103. // uninstall before
  104. _ = service.Control(s, "stop")
  105. _ = service.Control(s, "uninstall")
  106. binPath := install.InstallNps()
  107. svcConfig.Executable = binPath
  108. s, err := service.New(prg, svcConfig)
  109. if err != nil {
  110. logs.Error(err)
  111. return
  112. }
  113. err = service.Control(s, os.Args[1])
  114. if err != nil {
  115. logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
  116. }
  117. return
  118. case "start", "restart", "stop", "uninstall":
  119. err := service.Control(s, os.Args[1])
  120. if err != nil {
  121. logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
  122. }
  123. return
  124. case "update":
  125. install.UpdateNps()
  126. return
  127. default:
  128. logs.Error("command is not support")
  129. return
  130. }
  131. }
  132. _ = s.Run()
  133. }
  134. type nps struct {
  135. exit chan struct{}
  136. }
  137. func (p *nps) Start(s service.Service) error {
  138. _, _ = s.Status()
  139. _ = p.run()
  140. return nil
  141. }
  142. func (p *nps) Stop(s service.Service) error {
  143. _, _ = s.Status()
  144. close(p.exit)
  145. if service.Interactive() {
  146. os.Exit(0)
  147. }
  148. return nil
  149. }
  150. func (p *nps) run() error {
  151. defer func() {
  152. if err := recover(); err != nil {
  153. const size = 64 << 10
  154. buf := make([]byte, size)
  155. buf = buf[:runtime.Stack(buf, false)]
  156. logs.Warning("nps: panic serving %v: %v\n%s", err, string(buf))
  157. }
  158. }()
  159. routers.Init()
  160. task := &file.Tunnel{
  161. Mode: "webServer",
  162. }
  163. bridgePort, err := beego.AppConfig.Int("bridge_port")
  164. if err != nil {
  165. logs.Error("Getting bridge_port error", err)
  166. os.Exit(0)
  167. }
  168. logs.Info("the version of server is %s ,allow client core version to be %s", version.VERSION, version.GetVersion())
  169. connection.InitConnectionService()
  170. crypt.InitTls(filepath.Join(common.GetRunPath(), "conf", "server.pem"), filepath.Join(common.GetRunPath(), "conf", "server.key"))
  171. tool.InitAllowPort()
  172. tool.StartSystemInfo()
  173. go server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"))
  174. select {
  175. case <-p.exit:
  176. logs.Warning("stop...")
  177. }
  178. return nil
  179. }