diff --git a/.travis.yml b/.travis.yml index f076c5c..d5c3457 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ script: os: - linux before_deploy: - - chmod +x ./build.sh && ./build.sh + - chmod +x ./build.sh && chmod +x ./build.android.sh && ./build.sh deploy: provider: releases @@ -44,14 +44,15 @@ deploy: - linux_mipsle_server.tar.gz - linux_mips_client.tar.gz - linux_mips_server.tar.gz - - macos_client.tar.gz - - macos_server.tar.gz - - win_386_client.tar.gz - - win_386_server.tar.gz - - win_amd64_client.tar.gz - - win_amd64_server.tar.gz + - darwin_amd64_client.tar.gz + - darwin_amd64_server.tar.gz + - windows_386_client.tar.gz + - windows_386_server.tar.gz + - windows_amd64_client.tar.gz + - windows_amd64_server.tar.gz - npc_syno.spk - npc_sdk.tar.gz + - android_client.apk on: tags: true all_branches: true diff --git a/README.md b/README.md index 8ef2b90..d1f8958 100644 --- a/README.md +++ b/README.md @@ -28,19 +28,32 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务 下载对应的系统版本即可,服务端和客户端是单独的 ### 服务端启动 -1. 进入服务端启动 -```shell - ./nps -``` -如有错误修改配置文件相应端口,无错误可继续进行下去 +下载完服务器压缩包后,解压,然后进入解压后的文件夹 -2. 访问服务端ip:web服务端口(默认为8024) -3. 使用用户名和密码登陆(默认admin/123,正式使用一定要更改) -4. 在web中创建客户端 +- 执行安装命令 + +对于linux|darwin ```sudo ./nps install``` + +对于windows,管理员身份运行cmd,进入安装目录 ```nps.exe install``` + +- 启动 + +对于linux|darwin ```sudo nps start``` + +对于windows,管理员身份运行cmd,进入程序目录 ```nps.exe start``` + +停止和重启可用,stop和restart + +**如果发现没有启动成功,可以查看日志(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log)** +- 访问服务端ip:web服务端口(默认为8080) +- 使用用户名和密码登陆(默认admin/123,正式使用一定要更改) +- 创建客户端 ### 客户端连接 -1. 点击web管理中客户端前的+号,复制启动命令 -2. 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行 +- 点击web管理中客户端前的+号,复制启动命令 +- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行 + +如果需要注册到系统服务可查看[注册到系统服务](https://cnlh.github.io/nps/#/use?id=注册到系统服务) ### 配置 - 客户端连接后,在web中配置对应穿透服务即可 diff --git a/build.android.sh b/build.android.sh new file mode 100644 index 0000000..cae6d93 --- /dev/null +++ b/build.android.sh @@ -0,0 +1,17 @@ +#/bin/bash +#sudo apt-get install libgl1-mesa-dev xorg-dev +#go get github.com/ffdfgdfg/fyne-cross +#fyne-cross --targets=linux/amd64,windows/amd64,darwin/amd64 gui/npc/npc.go + +mkdir -p /go/src/github.com/cnlh/nps +cp -R * /go/src/github.com/cnlh/nps +cd /go/src/github.com/cnlh/nps +go get -u fyne.io/fyne fyne.io/fyne/cmd/fyne +go mod vendor +cd vendor +cp -R * /go/src +cd .. +rm -rf vendor +cd gui/npc +fyne package -os android -appID org.nps.client -icon ../../docs/logo.png +mv npc.apk /app/android_client.apk diff --git a/build.bash b/build.bash deleted file mode 100755 index b7296ca..0000000 --- a/build.bash +++ /dev/null @@ -1,136 +0,0 @@ -#!/bin/bash -CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf linux_amd64_client.tar.gz npc conf/npc.conf - -CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf linux_386_client.tar.gz npc conf/npc.conf - -CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf freebsd_386_client.tar.gz npc conf/npc.conf - -CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf freebsd_amd64_client.tar.gz npc conf/npc.conf - -CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf freebsd_arm_client.tar.gz npc conf/npc.conf - -CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf linux_arm_client.tar.gz npc conf/npc.conf - - -CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf linux_arm64_client.tar.gz npc conf/npc.conf - - -CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf linux_mips64_client.tar.gz npc conf/npc.conf - - -CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf linux_mips64le_client.tar.gz npc conf/npc.conf - - -CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf linux_mipsle_client.tar.gz npc conf/npc.conf - - -CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf linux_mips_client.tar.gz npc conf/npc.conf - - -CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf win_386_client.tar.gz npc.exe conf/npc.conf - - -CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf win_amd64_client.tar.gz npc.exe conf/npc.conf - - -CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -upx npc -tar -czvf macos_client.tar.gz npc conf/npc.conf - - - -CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf linux_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - -CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf linux_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - -CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf linux_arm_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - - -CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf linux_arm64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - - -CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf freebsd_arm_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - - -CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf freebsd_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - - -CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf freebsd_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - - - -CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf linux_mips_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - - -CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf linux_mips64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - - -CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf linux_mips64le_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - - -CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf linux_mipsle_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - - - -CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps -tar -czvf macos_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps - - -CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps.exe -tar -czvf win_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe - - -CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -upx nps.exe -tar -czvf win_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe - diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 index df967c4..56e77f9 --- a/build.sh +++ b/build.sh @@ -1,5 +1,5 @@ #/bash/sh -export VERSION=0.25.1 +export VERSION=0.25.2 sudo apt-get install gcc-mingw-w64-i686 env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go @@ -69,17 +69,17 @@ tar -czvf linux_mips_client.tar.gz npc conf/npc.conf conf/multi_account.conf CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -tar -czvf win_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf +tar -czvf windows_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -tar -czvf win_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf +tar -czvf windows_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go -tar -czvf macos_client.tar.gz npc conf/npc.conf conf/multi_account.conf +tar -czvf darwin_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go @@ -146,23 +146,24 @@ tar -czvf linux_mipsle_server.tar.gz conf/nps.conf conf/tasks.json conf/clients. CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -tar -czvf macos_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps +tar -czvf darwin_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -tar -czvf win_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe +tar -czvf windows_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go -tar -czvf win_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe +tar -czvf windows_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" sudo apt-get update sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce docker --version +docker run --rm -i -w /app -v $(pwd):/app -e ANDROID_HOME=/usr/local/android_sdk ffdfgdfg/fyne-cross:android /app/build.android.sh git clone https://github.com/cnlh/spksrc.git ~/spksrc mkdir ~/spksrc/nps && cp -rf ./* ~/spksrc/nps/ docker run -itd --name spksrc --env VERSION=$VERSION -v ~/spksrc:/spksrc synocommunity/spksrc /bin/bash diff --git a/cmd/npc/npc.go b/cmd/npc/npc.go index fe5b3f5..ddce289 100644 --- a/cmd/npc/npc.go +++ b/cmd/npc/npc.go @@ -3,18 +3,19 @@ package main import ( "flag" "fmt" - "os" - "strings" - "time" - "github.com/astaxie/beego/logs" "github.com/ccding/go-stun/stun" "github.com/cnlh/nps/client" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/config" - "github.com/cnlh/nps/lib/daemon" "github.com/cnlh/nps/lib/file" + "github.com/cnlh/nps/lib/install" "github.com/cnlh/nps/lib/version" + "github.com/kardianos/service" + "os" + "runtime" + "strings" + "time" ) var ( @@ -30,11 +31,60 @@ var ( password = flag.String("password", "", "p2p password flag") target = flag.String("target", "", "p2p target") localType = flag.String("local_type", "p2p", "p2p target") - logPath = flag.String("log_path", "npc.log", "npc log path") + logPath = flag.String("log_path", "", "npc log path") + debug = flag.Bool("debug", true, "npc debug") ) func main() { flag.Parse() + logs.Reset() + logs.EnableFuncCallDepth(true) + logs.SetLogFuncCallDepth(3) + if *logPath == "" { + *logPath = common.GetNpcLogPath() + } + if common.IsWindows() { + *logPath = strings.Replace(*logPath, "\\", "\\\\", -1) + } + if *debug { + logs.SetLogger(logs.AdapterConsole, `{"level":`+*logLevel+`,"color":true}`) + } else { + logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"`+*logPath+`","daily":false,"maxlines":100000,"color":true}`) + } + + // init service + options := make(service.KeyValue) + options["Restart"] = "on-success" + options["SuccessExitStatus"] = "1 2 8 SIGKILL" + svcConfig := &service.Config{ + Name: "Npc", + DisplayName: "nps内网穿透客户端", + Description: "一款轻量级、功能强大的内网穿透代理服务器。支持tcp、udp流量转发,支持内网http代理、内网socks5代理,同时支持snappy压缩、站点保护、加密传输、多路复用、header修改等。支持web图形化管理,集成多用户模式。", + Option: options, + } + if !common.IsWindows() { + svcConfig.Dependencies = []string{ + "Requires=network.target", + "After=network-online.target syslog.target"} + } + for _, v := range os.Args[1:] { + switch v { + case "install", "start", "stop", "uninstall", "restart": + continue + } + if !strings.Contains(v, "-service=") && !strings.Contains(v, "-debug=") { + svcConfig.Arguments = append(svcConfig.Arguments, v) + } + } + svcConfig.Arguments = append(svcConfig.Arguments, "-debug=false") + prg := &npc{ + exit: make(chan struct{}), + } + s, err := service.New(prg, svcConfig) + if err != nil { + logs.Error(err) + return + } if len(os.Args) >= 2 { switch os.Args[1] { case "status": @@ -45,6 +95,9 @@ func main() { case "register": flag.CommandLine.Parse(os.Args[2:]) client.RegisterLocalIp(*serverAddr, *verifyKey, *connType, *proxyUrl, *registerTime) + case "update": + install.UpdateNpc() + return case "nat": nat, host, err := stun.NewClient().Discover() if err != nil || host == nil { @@ -53,16 +106,45 @@ func main() { } fmt.Printf("nat type: %s \npublic address: %s\n", nat.String(), host.String()) os.Exit(0) + case "install", "start", "stop", "uninstall", "restart": + if os.Args[1] == "install" { + install.InstallNpc() + } + err := service.Control(s, os.Args[1]) + if err != nil { + logs.Error("Valid actions: %q\n", service.ControlAction, err.Error()) + } + return } } - daemon.InitDaemon("npc", common.GetRunPath(), common.GetTmpPath()) - logs.EnableFuncCallDepth(true) - logs.SetLogFuncCallDepth(3) - if *logType == "stdout" { - logs.SetLogger(logs.AdapterConsole, `{"level":`+*logLevel+`,"color":true}`) - } else { - logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"`+*logPath+`","daily":false,"maxlines":100000,"color":true}`) + s.Run() +} + +type npc struct { + exit chan struct{} +} + +func (p *npc) Start(s service.Service) error { + go p.run() + return nil +} +func (p *npc) Stop(s service.Service) error { + close(p.exit) + if service.Interactive() { + os.Exit(0) } + return nil +} + +func (p *npc) run() error { + defer func() { + if err := recover(); err != nil { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + logs.Warning("npc: panic serving %v: %v\n%s", err, string(buf)) + } + }() //p2p or secret command if *password != "" { commonConfig := new(config.CommonConfig) @@ -76,8 +158,8 @@ func main() { localServer.Port = *localPort commonConfig.Client = new(file.Client) commonConfig.Client.Cnf = new(file.Config) - client.StartLocalServer(localServer, commonConfig) - return + go client.StartLocalServer(localServer, commonConfig) + return nil } env := common.GetEnvMap() if *serverAddr == "" { @@ -88,15 +170,22 @@ func main() { } logs.Info("the version of client is %s, the core version of client is %s", version.VERSION, version.GetVersion()) if *verifyKey != "" && *serverAddr != "" && *configPath == "" { - for { - client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl, nil).Start() - logs.Info("It will be reconnected in five seconds") - time.Sleep(time.Second * 5) - } + go func() { + for { + client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl, nil).Start() + logs.Info("It will be reconnected in five seconds") + time.Sleep(time.Second * 5) + } + }() } else { if *configPath == "" { - *configPath = "npc.conf" + *configPath = "conf/npc.conf" } - client.StartFromFile(*configPath) + go client.StartFromFile(*configPath) } + select { + case <-p.exit: + logs.Warning("stop...") + } + return nil } diff --git a/cmd/nps/nps.go b/cmd/nps/nps.go index 98f13af..95ddf9c 100644 --- a/cmd/nps/nps.go +++ b/cmd/nps/nps.go @@ -2,9 +2,12 @@ package main import ( "flag" + "github.com/cnlh/nps/lib/install" "log" "os" "path/filepath" + "runtime" + "strings" "github.com/astaxie/beego" "github.com/astaxie/beego/logs" @@ -12,14 +15,13 @@ import ( "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/daemon" "github.com/cnlh/nps/lib/file" - "github.com/cnlh/nps/lib/install" "github.com/cnlh/nps/lib/version" "github.com/cnlh/nps/server" "github.com/cnlh/nps/server/connection" - "github.com/cnlh/nps/server/test" "github.com/cnlh/nps/server/tool" "github.com/cnlh/nps/web/routers" + "github.com/kardianos/service" ) var ( @@ -29,20 +31,9 @@ var ( func main() { flag.Parse() - beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "nps.conf")) - routers.Init() - if len(os.Args) > 1 { - switch os.Args[1] { - case "test": - test.TestServerConfig() - log.Println("test ok, no error") - return - case "start", "restart", "stop", "status", "reload": - daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath()) - case "install": - install.InstallNps() - return - } + // init log + if err := beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "nps.conf")); err != nil { + log.Fatalln("load config file error", err.Error()) } if level = beego.AppConfig.String("log_level"); level == "" { level = "7" @@ -50,11 +41,102 @@ func main() { logs.Reset() logs.EnableFuncCallDepth(true) logs.SetLogFuncCallDepth(3) - if *logType == "stdout" { - logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`) - } else { - logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+beego.AppConfig.String("log_path")+`","daily":false,"maxlines":100000,"color":true}`) + logPath := beego.AppConfig.String("log_path") + if logPath == "" { + logPath = common.GetLogPath() } + if common.IsWindows() { + logPath = strings.Replace(logPath, "\\", "\\\\", -1) + } + logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+logPath+`","daily":false,"maxlines":100000,"color":true}`) + // init service + options := make(service.KeyValue) + options["Restart"] = "on-success" + options["SuccessExitStatus"] = "1 2 8 SIGKILL" + svcConfig := &service.Config{ + Name: "Nps", + DisplayName: "nps内网穿透代理服务器", + Description: "一款轻量级、功能强大的内网穿透代理服务器。支持tcp、udp流量转发,支持内网http代理、内网socks5代理,同时支持snappy压缩、站点保护、加密传输、多路复用、header修改等。支持web图形化管理,集成多用户模式。", + Option: options, + } + if !common.IsWindows() { + svcConfig.Dependencies = []string{ + "Requires=network.target", + "After=network-online.target syslog.target"} + } + prg := &nps{} + prg.exit = make(chan struct{}) + s, err := service.New(prg, svcConfig) + if err != nil { + logs.Error(err) + return + } + if len(os.Args) > 1 { + switch os.Args[1] { + case "debug": + logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`) + case "reload": + daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath()) + return + case "install": + // uninstall before + service.Control(s, "uninstall") + + binPath := install.InstallNps() + svcConfig.Executable = binPath + s, err := service.New(prg, svcConfig) + if err != nil { + logs.Error(err) + return + } + err = service.Control(s, os.Args[1]) + if err != nil { + logs.Error("Valid actions: %q\n", service.ControlAction, err.Error()) + } + return + case "start", "restart", "stop", "uninstall": + err := service.Control(s, os.Args[1]) + if err != nil { + logs.Error("Valid actions: %q\n", service.ControlAction, err.Error()) + } + return + case "update": + install.UpdateNps() + return + default: + logs.Error("command is not support") + return + } + } + s.Run() +} + +type nps struct { + exit chan struct{} +} + +func (p *nps) Start(s service.Service) error { + p.run() + return nil +} +func (p *nps) Stop(s service.Service) error { + close(p.exit) + if service.Interactive() { + os.Exit(0) + } + return nil +} + +func (p *nps) run() error { + defer func() { + if err := recover(); err != nil { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + logs.Warning("nps: panic serving %v: %v\n%s", err, string(buf)) + } + }() + routers.Init() task := &file.Tunnel{ Mode: "webServer", } @@ -68,5 +150,10 @@ func main() { crypt.InitTls(filepath.Join(common.GetRunPath(), "conf", "server.pem"), filepath.Join(common.GetRunPath(), "conf", "server.key")) tool.InitAllowPort() tool.StartSystemInfo() - server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type")) + go server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type")) + select { + case <-p.exit: + logs.Warning("stop...") + } + return nil } diff --git a/conf/nps.conf b/conf/nps.conf index 8c22ab1..01f3e27 100755 --- a/conf/nps.conf +++ b/conf/nps.conf @@ -26,7 +26,7 @@ public_vkey=123 # log level LevelEmergency->0 LevelAlert->1 LevelCritical->2 LevelError->3 LevelWarning->4 LevelNotice->5 LevelInformational->6 LevelDebug->7 log_level=7 -log_path=nps.log +#log_path=nps.log #Whether to restrict IP access, true or false or ignore #ip_limit=true @@ -42,6 +42,9 @@ web_password=123 web_port = 8080 web_ip=0.0.0.0 web_base_url= +web_open_ssl=false +web_cert_file=conf/server.pem +web_key_file=conf/server.key # if web under proxy use sub path. like http://host/nps need this. #web_base_url=/nps diff --git a/docs/_sidebar.md b/docs/_sidebar.md index cfb58fa..a17588d 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -18,7 +18,8 @@ * [功能](feature.md) * [说明](description.md) * [web api](api.md) - + * [sdk](npc_sdk.md) +git * 其他 * [贡献](contribute.md) diff --git a/docs/description.md b/docs/description.md index 0520ad6..584f5b0 100644 --- a/docs/description.md +++ b/docs/description.md @@ -24,3 +24,6 @@ 默认情况下linux对连接数量有限制,对于性能好的机器完全可以调整内核参数以处理更多的连接。 `tcp_max_syn_backlog` `somaxconn` 酌情调整参数,增强网络性能 + +## web管理保护 +当一个ip连续登陆失败次数超过10次,将在一分钟内禁止该ip再次尝试。 diff --git a/docs/example.md b/docs/example.md index e37c1f6..acaab93 100644 --- a/docs/example.md +++ b/docs/example.md @@ -25,7 +25,7 @@ 现在访问(http|https://)`a.proxy.com`,`b.proxy.com`即可成功 -**https:** 如需使用https请进行相关配置,详见 [使用https](##使用https) +**https:** 如需使用https请进行相关配置,详见 [使用https](/nps_extend?id=使用https) ## tcp隧道 @@ -100,7 +100,7 @@ ## p2p服务 -**适用范围:** 大流量传输场景,流量不经过公网服务器,但是由于p2p穿透和nat类型关系较大,不保证100%成功,支持大部分nat类型。[nat类型检测](##nat类型检测) +**适用范围:** 大流量传输场景,流量不经过公网服务器,但是由于p2p穿透和nat类型关系较大,不保证100%成功,支持大部分nat类型。[nat类型检测](/npc_extend?id=nat类型检测) **假设场景:** diff --git a/docs/index.html b/docs/index.html index c86cf55..caaab9b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -11,7 +11,10 @@
+ + - diff --git a/docs/logo.png b/docs/logo.png index 20df9d0..b4e29a7 100644 Binary files a/docs/logo.png and b/docs/logo.png differ diff --git a/docs/npc_sdk.md b/docs/npc_sdk.md new file mode 100644 index 0000000..db70772 --- /dev/null +++ b/docs/npc_sdk.md @@ -0,0 +1,23 @@ +# npc sdk文档 + +``` +命令行模式启动客户端 +p0->连接地址 +p1->vkey +p2->连接类型(tcp or udp) +p3->连接代理 + +extern GoInt StartClientByVerifyKey(char* p0, char* p1, char* p2, char* p3); + +查看当前启动的客户端状态,在线为1,离线为0 +extern GoInt GetClientStatus(); + +关闭客户端 +extern void CloseClient(); + +获取当前客户端版本 +extern char* Version(); + +获取日志,实时更新 +extern char* Logs(); +``` diff --git a/docs/nps_extend.md b/docs/nps_extend.md index e15ca8e..5208667 100644 --- a/docs/nps_extend.md +++ b/docs/nps_extend.md @@ -44,7 +44,8 @@ server { } } ``` - +## web管理使用https +如果web管理需要使用https,可以在配置文件`nps.conf`中设置`web_open_ssl=true`,并配置`web_cert_file`和`web_key_file` ## web使用Caddy代理 如果将web配置到Caddy代理,实现子路径访问nps,可以这样配置. diff --git a/docs/nps_use.md b/docs/nps_use.md index 1985811..4058869 100644 --- a/docs/nps_use.md +++ b/docs/nps_use.md @@ -1,57 +1,43 @@ +# 使用 **提示:使用web模式时,服务端执行文件必须在项目根目录,否则无法正确加载配置文件** - -# 服务端测试 -```shell - ./nps test -``` -如有错误请及时修改配置文件,无错误可继续进行下去 -# 服务端启动 -```shell - ./nps start -``` -**如果无需daemon运行或者打开后无法正常访问web管理,去掉start查看日志运行即可** - -# web管理 +## web管理 进入web界面,公网ip:web界面端口(默认8080),密码默认为123 进入web管理界面,有详细的说明 -# 服务端配置文件重载 -如果是daemon启动 +## 服务端配置文件重载 +对于linux、darwin ```shell - ./nps reload + sudo nps reload +``` +对于windows +```shell + nps.exe reload ``` **说明:** 仅支持部分配置重载,例如`allow_user_login` `auth_crypt_key` `auth_key` `web_username` `web_password` 等,未来将支持更多 -# 服务端停止或重启 -如果是daemon启动 +## 服务端停止或重启 +对于linux、darwin ```shell - ./nps stop|restart -``` - -# 将nps安装到系统 -如果需要长期并且方便的运行nps服务端,可将nps安装到操作系统中,可执行命令 - -``` -(./nps|nps.exe) install -``` -安装成功后,对于linux,darwin,将会把配置文件和静态文件放置于/etc/nps/,并将可执行文件nps复制到/usr/bin/nps或者/usr/local/bin/nps,安装成功后可在任何位置执行,同时也会添加systemd配置。 - -``` -sudo systemctl enable|disable|start|stop|restart|status nps -``` -systemd,带有开机自启,自动重启配置,当进程结束后15秒会启动,日志输出至/var/log/nps/nps.log。 -建议采用此方式启动,能够捕获panic信息,便于排查问题。 - -``` -nps test|start|stop|restart|status -``` -对于windows系统,将会把配置文件和静态文件放置于C:\Program Files\nps,安装成功后可将可执行文件nps.exe复制到任何位置执行 - -``` -nps.exe test|start|stop|restart|status + sudo nps stop|restart +``` +对于windows +```shell + nps.exe stop|restart +``` +## 服务端更新 +请首先执行`sudo nps stop`或者`nps.exe stop`停止运行,然后 + +对于linux +```shell + sudo nps-update update +``` +对于windows +```shell + nps-update.exe update ``` +更新完成后,执行执行`sudo nps start`或者`nps.exe start`重新运行即可完成升级 \ No newline at end of file diff --git a/docs/run.md b/docs/run.md index c0aec66..bc79756 100644 --- a/docs/run.md +++ b/docs/run.md @@ -1,19 +1,32 @@ # 启动 ## 服务端 下载完服务器压缩包后,解压,然后进入解压后的文件夹 -1. 执行命令启动 -```shell - ./nps -``` -**如有错误(E)修改配置文件相应端口**,无错误可继续进行下去 -2. 访问服务端ip:web服务端口(默认为8024) -3. 使用用户名和密码登陆(默认admin/123,正式使用一定要更改) -4. 创建客户端 + +- 执行安装命令 + +对于linux|darwin ```sudo ./nps install``` + +对于windows,管理员身份运行cmd,进入安装目录 ```nps.exe install``` + +- 启动 + +对于linux|darwin ```sudo nps start``` + +对于windows,管理员身份运行cmd,进入程序目录 ```nps.exe start``` + +停止和重启可用,stop和restart + +**如果发现没有启动成功,可以使用`nps(.exe) debug`运行调试,或查看日志**(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log) +- 访问服务端ip:web服务端口(默认为8080) +- 使用用户名和密码登陆(默认admin/123,正式使用一定要更改) +- 创建客户端 ## 客户端 -1. 下载客户端安装包并解压,进入到解压目录 -1. 点击web管理中客户端前的+号,复制启动命令 -2. 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行 +- 下载客户端安装包并解压,进入到解压目录 +- 点击web管理中客户端前的+号,复制启动命令 +- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行 + +如果需要注册到系统服务可查看[注册到系统服务](/use?id=注册到系统服务) ## 配置 - 客户端连接后,在web中配置对应穿透服务即可 diff --git a/docs/use.md b/docs/use.md index 183d41e..5ac6cce 100644 --- a/docs/use.md +++ b/docs/use.md @@ -2,34 +2,45 @@ ## 无配置文件模式 此模式的各种配置在服务端web管理中完成,客户端除运行一条命令外无需任何其他设置 ``` - ./npc -server=ip:port -vkey=web界面中显示的密钥 + ./npc -debug=true -server=ip:port -vkey=web界面中显示的密钥 ``` +## 注册到系统服务 +对于linux、darwin +- 注册:`sudo ./npc install 其他参数(例如-server=xx -vkey=xx或者-config=xxx)` +- 启动:`sudo ./npc start` +- 停止:`sudo ./npc stop` +- 如果需要更换命令内容需要先卸载`./npc -service=uninstall`,再重新注册 + +对于windows,使用管理员身份运行cmd + +- 注册:`npc.exe install 其他参数(例如-server=xx -vkey=xx或者-config=xxx)` +- 启动:`npc.exe start` +- 停止:`npc.exe stop` +- 如果需要更换命令内容需要先卸载`npc.exe -service=uninstall`,再重新注册 + +注册到服务后,日志文件windows位于当前目录下,linux和darwin位于/var/log/npc.log + +## 客户端更新 +首先进入到对于的客户端二进制文件目录 + +请首先执行`sudo ./npc stop`或者`nps.exe stop`停止运行,然后 + +对于linux +```shell + sudo ./npc-update update +``` +对于windows +```shell +npc-update.exe update +``` + +更新完成后,执行执行`sudo nps start`或者`nps.exe start`重新运行即可完成升级 + ## 配置文件模式 此模式使用nps的公钥或者客户端私钥验证,各种配置在客户端完成,同时服务端web也可以进行管理 ``` ./npc -config=npc配置文件路径 ``` -可自行添加systemd service,例如:`npc.service` -``` -[Unit] -Description=npc - convenient proxy server client -Documentation=https://github.com/cnlh/nps/ -After=network-online.target remote-fs.target nss-lookup.target -Wants=network-online.target - -[Service] -Type=simple -KillMode=process -Restart=always -RestartSec=15s -StandardOutput=append:/var/log/nps/npc.log -ExecStartPre=/bin/echo 'Starting npc' -ExecStopPost=/bin/echo 'Stopping npc' -ExecStart=/absolutely path to/npc -server=ip:port -vkey=web界面中显示的密钥 - -[Install] -WantedBy=multi-user.target -``` ## 配置文件说明 [示例配置文件](https://github.com/cnlh/nps/tree/master/conf/npc.conf) #### 全局配置 diff --git a/go.mod b/go.mod index a2b0199..141d73c 100644 --- a/go.mod +++ b/go.mod @@ -1,28 +1,32 @@ module github.com/cnlh/nps -go 1.12 +go 1.13 require ( + fyne.io/fyne v1.2.0 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/astaxie/beego v1.12.0 - github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff // indirect + github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c // indirect + github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d + github.com/dsnet/compress v0.0.1 // indirect github.com/go-ole/go-ole v1.2.4 // indirect github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db + github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 // indirect + github.com/kardianos/service v1.0.0 github.com/klauspost/cpuid v1.2.1 // indirect + github.com/klauspost/pgzip v1.2.1 // indirect github.com/klauspost/reedsolomon v1.9.2 // indirect - github.com/onsi/gomega v1.5.0 // indirect github.com/panjf2000/ants/v2 v2.2.2 - github.com/pkg/errors v0.8.0 + github.com/pkg/errors v0.8.1 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect github.com/shirou/gopsutil v2.19.11+incompatible - github.com/stretchr/testify v1.3.0 // indirect github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect github.com/tjfoc/gmsm v1.0.1 // indirect github.com/xtaci/kcp-go v5.4.4+incompatible github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect - golang.org/x/net v0.0.0-20181114220301-adae6a3d119a + golang.org/x/net v0.0.0-20181220203305-927f97764cc3 golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect ) diff --git a/go.sum b/go.sum index 428e5a8..a1c8f67 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,18 @@ +fyne.io/fyne v1.2.0 h1:mdp7Cs7QmSJTeazYxEDa9wWeJNig7paBcjm0dooFtLE= +fyne.io/fyne v1.2.0/go.mod h1:Ab+3DIB/FVteW0y4DXfmZv4N3JdnCBh2lHkINI02BOU= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I= github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/astaxie/beego v1.12.0 h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y= -github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= -github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff/go.mod h1:PhH1ZhyCzHKt4uAasyx+ljRCgoezetRNf59CUtwUkqY= github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= +github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c h1:FUUopH4brHNO2kJoNN3pV+OBEYmgraLT/KHZrMM69r0= +github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= +github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c h1:aprLqMn7gSPT+vdDSl+/E6NLEuArwD/J7IWd8bJt5lQ= +github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c/go.mod h1:Ie6SubJv/NTO9Q0UBH0QCl3Ve50lu9hjbi5YJUw03TE= github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io= github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE= @@ -18,52 +23,75 @@ github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFl github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= +github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8xeGrhsjrI= github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= -github.com/exfly/beego v1.12.0 h1:OXwIwngaAx35Mga+jLiZmArusBxj8/H0jYXzGDAdwOg= -github.com/exfly/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw= +github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= +github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f h1:7MsFMbSn8Lcw0blK4+NEOf8DuHoOBDhJsHz04yh13pM= +github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= +github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 h1:WgfvpuKg42WVLkxNwzfFraXkTXPK36bMqXvMFN67clI= +github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214/go.mod h1:kj6hFWqfwSjFjLnYW5PK1DoxZ4O0uapwHRmd9jhln4E= +github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc= +github.com/josephspurrier/goversioninfo v0.0.0-20190124120936-8611f5a5ff3f/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE= +github.com/kardianos/service v1.0.0 h1:HgQS3mFfOlyntWX8Oke98JcJLqt1DBcHR4kxShpYef0= +github.com/kardianos/service v1.0.0/go.mod h1:8CzDhVuCuugtsHyZoTvsOBuvonN/UDBvl0kH+BUxvbo= +github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM= +github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/reedsolomon v1.9.2 h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18= github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/panjf2000/ants/v2 v2.2.2 h1:TWzusBjq/IflXhy+/S6u5wmMLCBdJnB9tPIx9Zmhvok= github.com/panjf2000/ants/v2 v2.2.2/go.mod h1:1GFm8bV8nyCQvU5K4WvBCTG1/YBFOD2VzjffD8fV55A= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= -github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM= -github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v2.19.11+incompatible h1:lJHR0foqAjI4exXqWsU3DbH7bX1xvdhGdnXTIARA9W4= github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/srwiley/oksvg v0.0.0-20190829233741-58e08c8fe40e h1:LJUrNHytcMXWKxnULIHPe5SCb1jDpO9o672VB1x2EuQ= +github.com/srwiley/oksvg v0.0.0-20190829233741-58e08c8fe40e/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= +github.com/srwiley/rasterx v0.0.0-20181219215540-696f7edb7a7e h1:FFotfUvew9Eg02LYRl8YybAnm0HCwjjfY5JlOI1oB00= +github.com/srwiley/rasterx v0.0.0-20181219215540-696f7edb7a7e/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709 h1:Ko2LQMrRU+Oy/+EDBwX7eZ2jp3C47eDBB8EIhKTun+I= +github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= @@ -71,6 +99,8 @@ github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b h1:mnG1fcsIB1d/3vbkB github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= github.com/tjfoc/gmsm v1.0.1 h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU= github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= +github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8= +github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= github.com/xtaci/kcp-go v5.4.4+incompatible h1:QIJ0a0Q0N1G20yLHL2+fpdzyy2v/Cb3PI+xiwx/KK9c= github.com/xtaci/kcp-go v5.4.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= @@ -78,17 +108,25 @@ github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+A github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 h1:idBdZTd9UioThJp8KpM/rTSinK/ChZFBE43/WtIy8zg= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/gui/npc/npc.go b/gui/npc/npc.go new file mode 100644 index 0000000..0c55ed4 --- /dev/null +++ b/gui/npc/npc.go @@ -0,0 +1,173 @@ +package main + +import ( + "fmt" + "fyne.io/fyne" + "fyne.io/fyne/app" + "fyne.io/fyne/layout" + "fyne.io/fyne/widget" + "github.com/astaxie/beego/logs" + "github.com/cnlh/nps/client" + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/daemon" + "github.com/cnlh/nps/lib/version" + "io/ioutil" + "os" + "path" + "runtime" + "strings" + "time" +) + +func main() { + daemon.InitDaemon("npc", common.GetRunPath(), common.GetTmpPath()) + logs.SetLogger("store") + application := app.New() + window := application.NewWindow("Npc " + version.VERSION) + window.SetContent(WidgetScreen()) + window.Resize(fyne.NewSize(910, 350)) + + window.ShowAndRun() + +} + +var ( + start bool + status = "Start!" + connType = "tcp" + cl = new(client.TRPClient) +) + +func WidgetScreen() fyne.CanvasObject { + return fyne.NewContainerWithLayout(layout.NewBorderLayout(nil, nil, nil, nil), + makeMainTab(), + ) +} + +func makeMainTab() fyne.Widget { + serverPort := widget.NewEntry() + serverPort.SetPlaceHolder("Server:Port") + + vKey := widget.NewEntry() + vKey.SetPlaceHolder("Vkey") + + radio := widget.NewRadio([]string{"tcp", "kcp"}, func(s string) { connType = s }) + radio.Horizontal = true + + refreshCh := make(chan struct{}) + button := widget.NewButton(status, func() { + start = !start + if start { + status = "Stop!" + // init the npc + fmt.Println("submit", serverPort.Text, vKey.Text, connType) + sp, vk, ct := loadConfig() + if sp != serverPort.Text || vk != vKey.Text || ct != connType { + saveConfig(serverPort.Text, vKey.Text, connType) + } + cl = client.NewRPClient(serverPort.Text, vKey.Text, connType, "", nil) + go cl.Start() + } else { + // close the npc + status = "Start!" + if cl != nil { + go cl.Close() + cl = nil + } + } + refreshCh <- struct{}{} + }) + go func() { + for { + <-refreshCh + button.SetText(status) + } + }() + + lo := widget.NewMultiLineEntry() + lo.SetReadOnly(true) + lo.Resize(fyne.NewSize(910, 250)) + slo := widget.NewScrollContainer(lo) + slo.Resize(fyne.NewSize(910, 250)) + go func() { + for { + time.Sleep(time.Second) + lo.SetText(common.GetLogMsg()) + slo.Resize(fyne.NewSize(910, 250)) + } + }() + + sp, vk, ct := loadConfig() + if sp != "" && vk != "" && ct != "" { + serverPort.SetText(sp) + vKey.SetText(vk) + connType = ct + radio.SetSelected(ct) + } + + return widget.NewVBox( + widget.NewLabel("Npc "+version.VERSION), + serverPort, + vKey, + radio, + button, + slo, + ) +} + +func getDir() (dir string, err error) { + if runtime.GOOS != "android" { + dir, err = os.UserConfigDir() + if err != nil { + return + } + } else { + dir = "/data/data/org.nps.client/files" + } + return +} + +func saveConfig(host, vkey, connType string) { + data := strings.Join([]string{host, vkey, connType}, "\n") + ph, err := getDir() + if err != nil { + logs.Warn("not found config dir") + return + } + _ = os.Remove(path.Join(ph, "npc.conf")) + f, err := os.OpenFile(path.Join(ph, "npc.conf"), os.O_CREATE|os.O_WRONLY, 0644) + defer f.Close() + if err != nil { + logs.Error(err) + return + } + if _, err := f.Write([]byte(data)); err != nil { + f.Close() // ignore error; Write error takes precedence + logs.Error(err) + return + } +} + +func loadConfig() (host, vkey, connType string) { + ph, err := getDir() + if err != nil { + logs.Warn("not found config dir") + return + } + f, err := os.OpenFile(path.Join(ph, "npc.conf"), os.O_RDONLY, 0644) + defer f.Close() + if err != nil { + logs.Error(err) + return + } + data, err := ioutil.ReadAll(f) + if err != nil { + logs.Error(err) + return + } + li := strings.Split(string(data), "\n") + host = li[0] + vkey = li[1] + connType = li[2] + return +} diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index 96ebaec..cf4b988 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -41,6 +41,9 @@ func (Self *BasePackager) NewPac(contents ...interface{}) (err error) { } } Self.setLength() + if Self.Length > MAXIMUM_SEGMENT_SIZE { + err = errors.New("mux:packer: newpack content segment too large") + } return } @@ -77,6 +80,11 @@ func (Self *BasePackager) UnPack(reader io.Reader) (n uint16, err error) { } if int(Self.Length) > cap(Self.Content) { err = errors.New("unpack err, content length too large") + return + } + if Self.Length > MAXIMUM_SEGMENT_SIZE { + err = errors.New("mux:packer: unpack content segment too large") + return } Self.Content = Self.Content[:int(Self.Length)] //n, err := io.ReadFull(reader, Self.Content) @@ -273,10 +281,10 @@ func (addr *Addr) Decode(b []byte) error { pos := 1 switch addr.Type { case ipV4: - addr.Host = net.IP(b[pos:pos+net.IPv4len]).String() + addr.Host = net.IP(b[pos : pos+net.IPv4len]).String() pos += net.IPv4len case ipV6: - addr.Host = net.IP(b[pos:pos+net.IPv6len]).String() + addr.Host = net.IP(b[pos : pos+net.IPv6len]).String() pos += net.IPv6len case domainName: addrlen := int(b[pos]) diff --git a/lib/common/run.go b/lib/common/run.go index 30c63c1..569ff5c 100644 --- a/lib/common/run.go +++ b/lib/common/run.go @@ -48,9 +48,20 @@ func IsWindows() bool { func GetLogPath() string { var path string if IsWindows() { - path = GetAppPath() + path = filepath.Join(GetAppPath(), "nps.log") } else { - path = "/tmp" + path = "/var/log/nps.log" + } + return path +} + +//interface npc log file path +func GetNpcLogPath() string { + var path string + if IsWindows() { + path = filepath.Join(GetAppPath(), "npc.log") + } else { + path = "/var/log/npc.log" } return path } diff --git a/lib/common/util.go b/lib/common/util.go index 67f58cb..1db0d27 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -51,7 +51,10 @@ func DomainCheck(domain string) bool { func CheckAuth(r *http.Request, user, passwd string) bool { s := strings.SplitN(r.Header.Get("Authorization"), " ", 2) if len(s) != 2 { - return false + s = strings.SplitN(r.Header.Get("Proxy-Authorization"), " ", 2) + if len(s) != 2 { + return false + } } b, err := base64.StdEncoding.DecodeString(s[1]) diff --git a/lib/install/install.go b/lib/install/install.go index 7b03581..66bb28b 100644 --- a/lib/install/install.go +++ b/lib/install/install.go @@ -1,99 +1,149 @@ package install import ( + "encoding/json" "errors" "fmt" + "github.com/c4milo/unpackit" + "github.com/cnlh/nps/lib/common" "io" "io/ioutil" "log" + "net/http" "os" "path/filepath" + "runtime" "strings" - - "github.com/cnlh/nps/lib/common" ) -func InstallNps() { - unit := `[Unit] -Description=nps - convenient proxy server -Documentation=https://github.com/cnlh/nps/ -After=network-online.target remote-fs.target nss-lookup.target -Wants=network-online.target` - service := `[Service] -Type=simple -KillMode=process -Restart=always -RestartSec=15s -StandardOutput=append:/var/log/nps/nps.log -ExecStartPre=/bin/echo 'Starting nps' -ExecStopPost=/bin/echo 'Stopping nps' -ExecStart=` - install := `[Install] -WantedBy=multi-user.target` - - path := common.GetInstallPath() - if common.FileExists(path) { - log.Fatalf("the path %s has exist, does not support install", path) - } - MkidrDirAll(path, "conf", "web/static", "web/views") +func UpdateNps() { + destPath := downloadLatest("server") //复制文件到对应目录 - if err := CopyDir(filepath.Join(common.GetAppPath(), "web", "views"), filepath.Join(path, "web", "views")); err != nil { - log.Fatalln(err) - } - if err := CopyDir(filepath.Join(common.GetAppPath(), "web", "static"), filepath.Join(path, "web", "static")); err != nil { - log.Fatalln(err) - } - if err := CopyDir(filepath.Join(common.GetAppPath(), "conf"), filepath.Join(path, "conf")); err != nil { - log.Fatalln(err) - } + copyStaticFile(destPath, "nps") + fmt.Println("Update completed, please restart") +} +func UpdateNpc() { + destPath := downloadLatest("client") + //复制文件到对应目录 + copyStaticFile(destPath, "npc") + fmt.Println("Update completed, please restart") +} + +type release struct { + TagName string `json:"tag_name"` +} + +func downloadLatest(bin string) string { + // get version + data, err := http.Get("https://api.github.com/repos/cnlh/nps/releases/latest") + if err != nil { + log.Fatal(err.Error()) + } + b, err := ioutil.ReadAll(data.Body) + if err != nil { + log.Fatal(err) + } + rl := new(release) + json.Unmarshal(b, &rl) + version := rl.TagName + fmt.Println("the latest version is", version) + filename := runtime.GOOS + "_" + runtime.GOARCH + "_" + bin + ".tar.gz" + // download latest package + downloadUrl := fmt.Sprintf("https://github.com/cnlh/nps/releases/download/%s/%s", version, filename) + fmt.Println("download package from ", downloadUrl) + resp, err := http.Get(downloadUrl) + if err != nil { + log.Fatal(err.Error()) + } + destPath, err := unpackit.Unpack(resp.Body, "") + if err != nil { + log.Fatal(err) + } + if bin == "server" { + destPath = strings.Replace(destPath, "/web", "", -1) + destPath = strings.Replace(destPath, `\web`, "", -1) + destPath = strings.Replace(destPath, "/views", "", -1) + destPath = strings.Replace(destPath, `\views`, "", -1) + } else { + destPath = strings.Replace(destPath, `\conf`, "", -1) + destPath = strings.Replace(destPath, "/conf", "", -1) + } + return destPath +} + +func copyStaticFile(srcPath, bin string) string { + path := common.GetInstallPath() + if bin == "nps" { + //复制文件到对应目录 + if err := CopyDir(filepath.Join(srcPath, "web", "views"), filepath.Join(path, "web", "views")); err != nil { + log.Fatalln(err) + } + chMod(filepath.Join(path, "web", "views"), 0766) + if err := CopyDir(filepath.Join(srcPath, "web", "static"), filepath.Join(path, "web", "static")); err != nil { + log.Fatalln(err) + } + chMod(filepath.Join(path, "web", "static"), 0766) + } + binPath, _ := filepath.Abs(os.Args[0]) if !common.IsWindows() { - if _, err := copyFile(filepath.Join(common.GetAppPath(), "nps"), "/usr/bin/nps"); err != nil { - if _, err := copyFile(filepath.Join(common.GetAppPath(), "nps"), "/usr/local/bin/nps"); err != nil { + if _, err := copyFile(filepath.Join(srcPath, bin), "/usr/bin/"+bin); err != nil { + if _, err := copyFile(filepath.Join(srcPath, bin), "/usr/local/bin/"+bin); err != nil { log.Fatalln(err) } else { - os.Chmod("/usr/local/bin/nps", 0755) - service += "/usr/local/bin/nps" - log.Println("Executable files have been copied to", "/usr/local/bin/nps") + copyFile(filepath.Join(srcPath, "nps"), "/usr/local/bin/"+bin+"-update") + binPath = "/usr/local/bin/" + bin } } else { - os.Chmod("/usr/bin/nps", 0755) - service += "/usr/bin/nps" - log.Println("Executable files have been copied to", "/usr/bin/nps") + copyFile(filepath.Join(srcPath, "nps"), "/usr/bin/"+bin+"-update") + binPath = "/usr/bin/" + bin } - systemd := unit + "\n\n" + service + "\n\n" + install - if _, err := os.Stat("/usr/lib/systemd/system"); os.IsExist(err) { - _ = os.Remove("/usr/lib/systemd/system/nps.service") - err := ioutil.WriteFile("/usr/lib/systemd/system/nps.service", []byte(systemd), 0644) - if err != nil { - log.Println("Write systemd service err ", err) - } - } else if _, err := os.Stat("/lib/systemd/system"); os.IsExist(err) { - _ = os.Remove("/lib/systemd/system/nps.service") - err := ioutil.WriteFile("/lib/systemd/system/nps.service", []byte(systemd), 0644) - if err != nil { - log.Println("Write systemd service err ", err) - } - } else { - log.Println("Write systemd service fail, not found the systemd system path ") - } - - _ = os.Mkdir("/var/log/nps", 644) + } else { + copyFile(filepath.Join(srcPath, bin+".exe"), filepath.Join(common.GetAppPath(), bin+"-update.exe")) + copyFile(filepath.Join(srcPath, bin+".exe"), filepath.Join(common.GetAppPath(), bin+".exe")) } + chMod(binPath, 0755) + return binPath +} + +func InstallNpc() { + path := common.GetInstallPath() + if !common.FileExists(path) { + err := os.Mkdir(path, 0755) + if err != nil { + log.Fatal(err) + } + } + copyStaticFile(common.GetAppPath(), "npc") +} + +func InstallNps() string { + path := common.GetInstallPath() + if common.FileExists(path) { + MkidrDirAll(path, "web/static", "web/views") + } else { + MkidrDirAll(path, "conf", "web/static", "web/views") + // not copy config if the config file is exist + if err := CopyDir(filepath.Join(common.GetAppPath(), "conf"), filepath.Join(path, "conf")); err != nil { + log.Fatalln(err) + } + chMod(filepath.Join(path, "conf"), 0766) + } + binPath := copyStaticFile(common.GetAppPath(), "nps") log.Println("install ok!") log.Println("Static files and configuration files in the current directory will be useless") log.Println("The new configuration file is located in", path, "you can edit them") if !common.IsWindows() { log.Println(`You can start with: -sudo systemctl enable|disable|start|stop|restart|status nps -or: -nps test|start|stop|restart|status +nps start|stop|restart|uninstall|update or nps-update update anywhere!`) } else { log.Println(`You can copy executable files to any directory and start working with: -nps.exe test|start|stop|restart|status +nps.exe start|stop|restart|uninstall|update or nps-update.exe update now!`) } + chMod(common.GetLogPath(), 0777) + return binPath } func MkidrDirAll(path string, v ...string) { for _, item := range v { @@ -130,6 +180,9 @@ func CopyDir(srcPath string, destPath string) error { destNewPath := strings.Replace(path, srcPath, destPath, -1) log.Println("copy file ::" + path + " to " + destNewPath) copyFile(path, destNewPath) + if !common.IsWindows() { + chMod(destNewPath, 0766) + } } return nil }) @@ -182,3 +235,9 @@ func pathExists(path string) (bool, error) { } return false, err } + +func chMod(name string, mode os.FileMode) { + if !common.IsWindows() { + os.Chmod(name, mode) + } +} diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 8f6e31f..28ec1de 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -293,7 +293,8 @@ copyData: // reset to 60s if timeout and data still available Self.off = 0 if err != nil { - return // queue receive stop or time out, break the loop and return + Self.CloseWindow() // also close the window, to avoid read twice + return // queue receive stop or time out, break the loop and return } //logs.Warn("pop element", Self.element.l, Self.element.part) } @@ -361,14 +362,14 @@ func (Self *ReceiveWindow) release() { // common.ListElementPool.Put(Self.element) //} for { - Self.element = Self.bufQueue.TryPop() - if Self.element == nil { + ele := Self.bufQueue.TryPop() + if ele == nil { return } - if Self.element.Buf != nil { - common.WindowBuff.Put(Self.element.Buf) + if ele.Buf != nil { + common.WindowBuff.Put(ele.Buf) } - common.ListElementPool.Put(Self.element) + common.ListElementPool.Put(ele) } // release resource } diff --git a/lib/version/version.go b/lib/version/version.go index b3ffbb1..5c80ede 100644 --- a/lib/version/version.go +++ b/lib/version/version.go @@ -1,6 +1,6 @@ package version -const VERSION = "0.25.1" +const VERSION = "0.25.2" // Compulsory minimum version, Minimum downward compatibility to this version func GetVersion() string { diff --git a/server/proxy/tcp.go b/server/proxy/tcp.go index 5b04252..1f593ba 100755 --- a/server/proxy/tcp.go +++ b/server/proxy/tcp.go @@ -65,13 +65,21 @@ func (s *WebServer) Start() error { beego.BConfig.WebConfig.Session.SessionOn = true beego.SetStaticPath(beego.AppConfig.String("web_base_url")+"/static", filepath.Join(common.GetRunPath(), "web", "static")) beego.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views")) - if l, err := connection.GetWebManagerListener(); err == nil { + err := errors.New("Web management startup failure ") + var l net.Listener + if l, err = connection.GetWebManagerListener(); err == nil { beego.InitBeforeHTTPRun() - http.Serve(l, beego.BeeApp.Handlers) + if beego.AppConfig.String("web_open_ssl") == "true" { + keyPath := beego.AppConfig.String("web_key_file") + certPath := beego.AppConfig.String("web_cert_file") + err = http.ServeTLS(l, beego.BeeApp.Handlers, certPath, keyPath) + } else { + err = http.Serve(l, beego.BeeApp.Handlers) + } } else { logs.Error(err) } - return errors.New("Web management startup failure") + return err } func (s *WebServer) Close() error { diff --git a/update.sh b/update.sh deleted file mode 100644 index 3e0bfe3..0000000 --- a/update.sh +++ /dev/null @@ -1,50 +0,0 @@ -#/bash/sh -echo "start upgrading to the latest version" -if [ $1 == "latest" ] -then - version=`wget -qO- -t1 -T2 "https://api.github.com/repos/cnlh/nps/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g'` -else - version=$1 -fi -echo "the current latest version is "$version"" -download_base_url=https://github.com/cnlh/nps/releases/download/$version/ - -if [ $4 ] -then - filename=""$2"_"$3"_v"$4"_"server".tar.gz" -else - filename=""$2"_"$3"_"server".tar.gz" -fi -complete_download_url=""$download_base_url""$filename"" -echo "start download file from "$complete_download_url"" - -dir_name=`echo $RANDOM` -mkdir $dir_name && cd $dir_name -wget $complete_download_url >/dev/null 2>&1 -if [ ! -f "$filename" ]; then - echo "download file failed!" - rm -rf $dir_name - exit -fi - -echo "start extracting files" -mkdir nps -tar -xvf $filename -C ./nps >/dev/null 2>&1 -cd nps - -if [ -f "../../nps" ]; then - echo "replace "../../nps"!" - cp -rf nps ../../ -fi - -usr_dir=`which nps` - -if [ -f "$usr_dir" ]; then - echo "replace "$usr_dir"!" - cp -rf nps $usr_dir -fi - -cd ../../ && rm -rf $dir_name - -echo "update complete!" -echo -e "\033[32m please restart nps \033[0m" diff --git a/web/controllers/login.go b/web/controllers/login.go index 10da8d7..39c5c55 100755 --- a/web/controllers/login.go +++ b/web/controllers/login.go @@ -1,6 +1,9 @@ package controllers import ( + "math/rand" + "net" + "sync" "time" "github.com/astaxie/beego" @@ -13,12 +16,32 @@ type LoginController struct { beego.Controller } +var ipRecord sync.Map + +type record struct { + hasLoginFailTimes int + lastLoginTime time.Time +} + func (self *LoginController) Index() { self.Data["web_base_url"] = beego.AppConfig.String("web_base_url") self.Data["register_allow"], _ = beego.AppConfig.Bool("allow_user_register") self.TplName = "login/index.html" } func (self *LoginController) Verify() { + clearIprecord() + ip, _, _ := net.SplitHostPort(self.Ctx.Request.RemoteAddr) + if v, ok := ipRecord.Load(ip); ok { + vv := v.(*record) + if (time.Now().Unix() - vv.lastLoginTime.Unix()) >= 60 { + vv.hasLoginFailTimes = 0 + } + if vv.hasLoginFailTimes >= 10 { + self.Data["json"] = map[string]interface{}{"status": 0, "msg": "username or password incorrect"} + self.ServeJSON() + return + } + } var auth bool if self.GetString("password") == beego.AppConfig.String("web_password") && self.GetString("username") == beego.AppConfig.String("web_username") { self.SetSession("isAdmin", true) @@ -56,7 +79,14 @@ func (self *LoginController) Verify() { if auth { self.SetSession("auth", true) self.Data["json"] = map[string]interface{}{"status": 1, "msg": "login success"} + ipRecord.Delete(ip) } else { + if v, load := ipRecord.LoadOrStore(ip, &record{hasLoginFailTimes: 1, lastLoginTime: time.Now()}); load { + vv := v.(*record) + vv.lastLoginTime = time.Now() + vv.hasLoginFailTimes += 1 + ipRecord.Store(ip, vv) + } self.Data["json"] = map[string]interface{}{"status": 0, "msg": "username or password incorrect"} } self.ServeJSON() @@ -97,3 +127,17 @@ func (self *LoginController) Out() { self.SetSession("auth", false) self.Redirect(beego.AppConfig.String("web_base_url")+"/login/index", 302) } + +func clearIprecord() { + rand.Seed(time.Now().UnixNano()) + x := rand.Intn(100) + if x == 1 { + ipRecord.Range(func(key, value interface{}) bool { + v := value.(*record) + if time.Now().Unix()-v.lastLoginTime.Unix() >= 60 { + ipRecord.Delete(key) + } + return true + }) + } +}