diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f076c5c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,57 @@ +language: go + +go: + - "1.13" + - master +services: + - docker +script: + - go test -v ./cmd/nps/ +os: + - linux +before_deploy: + - chmod +x ./build.sh && ./build.sh + +deploy: + provider: releases + api_key: + secure: ${TOKEN} + skip_cleanup: true + file: + - freebsd_386_client.tar.gz + - freebsd_386_server.tar.gz + - freebsd_amd64_client.tar.gz + - freebsd_amd64_server.tar.gz + - freebsd_arm_client.tar.gz + - freebsd_arm_server.tar.gz + - linux_386_client.tar.gz + - linux_386_server.tar.gz + - linux_amd64_client.tar.gz + - linux_amd64_server.tar.gz + - linux_arm64_client.tar.gz + - linux_arm64_server.tar.gz + - linux_arm_v5_client.tar.gz + - linux_arm_v6_client.tar.gz + - linux_arm_v7_client.tar.gz + - linux_arm_v5_server.tar.gz + - linux_arm_v6_server.tar.gz + - linux_arm_v7_server.tar.gz + - linux_mips64le_client.tar.gz + - linux_mips64le_server.tar.gz + - linux_mips64_client.tar.gz + - linux_mips64_server.tar.gz + - linux_mipsle_client.tar.gz + - 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 + - npc_syno.spk + - npc_sdk.tar.gz + on: + tags: true + all_branches: true diff --git a/README.md b/README.md index 0f78bdb..9d67939 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ # nps ![](https://img.shields.io/github/stars/cnlh/nps.svg) ![](https://img.shields.io/github/forks/cnlh/nps.svg) [![Gitter](https://badges.gitter.im/cnlh-nps/community.svg)](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![Build Status](https://travis-ci.org/cnlh/nps.svg?branch=master)](https://travis-ci.org/cnlh/nps) nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**,可支持任何**tcp、udp**上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还**支持内网http代理、内网socks5代理**、**p2p等**,并带有功能强大的web管理端。 @@ -47,6 +48,7 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务 * [配置文件说明](#服务端配置文件) * [使用https](#使用https) * [与nginx配合](#与nginx配合) + * [web使用Caddy代理](#web使用Caddy代理) * [关闭http|https代理](#关闭代理) * [将nps安装到系统](#将nps安装到系统) * [流量数据持久化](#流量数据持久化) @@ -317,6 +319,7 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务 web_port | web管理端口 web_password | web界面管理密码 web_username | web界面管理账号 +web_base_url | web管理主路径,用于将web管理置于代理子路径后面 bridge_port | 服务端客户端通信端口 https_proxy_port | 域名代理https代理监听端口 http_proxy_port | 域名代理http代理监听端口 @@ -375,6 +378,29 @@ server { } } ``` + +### web使用Caddy代理 + +如果将web配置到Caddy代理,实现子路径访问nps,可以这样配置. + +假设我们想通过 `http://caddy_ip:caddy_port/nps` 来访问后台, Caddyfile 这样配置: + +```Caddyfile +caddy_ip:caddy_port/nps { + #server_ip 为 nps 服务器IP + #web_port 为 nps 后台端口 + proxy / http://server_ip:web_port/nps { + transparent + } +} +``` + +nps.conf 修改 `web_base_url` 为 `/nps` 即可 +``` +web_base_url=/nps +``` + + ### 关闭代理 如需关闭http代理可在配置文件中将http_proxy_port设置为空,如需关闭https代理可在配置文件中将https_proxy_port设置为空。 diff --git a/bridge/bridge.go b/bridge/bridge.go index ea5c282..7894b66 100755 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -27,14 +27,16 @@ type Client struct { tunnel *mux.Mux signal *conn.Conn file *mux.Mux + Version string retryTime int // it will be add 1 when ping not ok until to 3 will close the client } -func NewClient(t, f *mux.Mux, s *conn.Conn) *Client { +func NewClient(t, f *mux.Mux, s *conn.Conn, vs string) *Client { return &Client{ - signal: s, - tunnel: t, - file: f, + signal: s, + tunnel: t, + file: f, + Version: vs, } } @@ -166,16 +168,23 @@ func (s *Bridge) cliProcess(c *conn.Conn) { return } //version check - if b, err := c.GetShortContent(32); err != nil || string(b) != crypt.Md5(version.GetVersion()) { + if b, err := c.GetShortLenContent(); err != nil || string(b) != version.GetVersion() { logs.Info("The client %s version does not match", c.Conn.RemoteAddr()) c.Close() return } + //version get + var vs []byte + var err error + if vs, err = c.GetShortLenContent(); err != nil { + logs.Info("get client %s version error", err.Error()) + c.Close() + return + } //write server version to client c.Write([]byte(crypt.Md5(version.GetVersion()))) c.SetReadDeadlineBySecond(5) var buf []byte - var err error //get vKey from client if buf, err = c.GetShortContent(32); err != nil { c.Close() @@ -191,7 +200,7 @@ func (s *Bridge) cliProcess(c *conn.Conn) { s.verifySuccess(c) } if flag, err := c.ReadFlag(); err == nil { - s.typeDeal(flag, c, id) + s.typeDeal(flag, c, id, string(vs)) } else { logs.Warn(err, flag) } @@ -214,7 +223,7 @@ func (s *Bridge) DelClient(id int) { } //use different -func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) { +func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs string) { isPub := file.GetDb().IsPubClient(id) switch typeVal { case common.WORK_MAIN: @@ -223,17 +232,18 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) { return } //the vKey connect by another ,close the client of before - if v, ok := s.Client.LoadOrStore(id, NewClient(nil, nil, c)); ok { + if v, ok := s.Client.LoadOrStore(id, NewClient(nil, nil, c, vs)); ok { if v.(*Client).signal != nil { v.(*Client).signal.WriteClose() } v.(*Client).signal = c + v.(*Client).Version = vs } go s.GetHealthFromClient(id, c) logs.Info("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr()) case common.WORK_CHAN: muxConn := mux.NewMux(c.Conn, s.tunnelType) - if v, ok := s.Client.LoadOrStore(id, NewClient(muxConn, nil, nil)); ok { + if v, ok := s.Client.LoadOrStore(id, NewClient(muxConn, nil, nil, vs)); ok { v.(*Client).tunnel = muxConn } case common.WORK_CONFIG: @@ -254,7 +264,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) { } case common.WORK_FILE: muxConn := mux.NewMux(c.Conn, s.tunnelType) - if v, ok := s.Client.LoadOrStore(id, NewClient(nil, muxConn, nil)); ok { + if v, ok := s.Client.LoadOrStore(id, NewClient(nil, muxConn, nil, vs)); ok { v.(*Client).file = muxConn } case common.WORK_P2P: @@ -419,7 +429,7 @@ loop: } c.WriteAddOk() c.Write([]byte(client.VerifyKey)) - s.Client.Store(client.Id, NewClient(nil, nil, nil)) + s.Client.Store(client.Id, NewClient(nil, nil, nil, "")) } case common.NEW_HOST: h, err := c.GetHostInfo() diff --git a/build.bash b/build.bash new file mode 100755 index 0000000..b7296ca --- /dev/null +++ b/build.bash @@ -0,0 +1,136 @@ +#!/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 new file mode 100644 index 0000000..1df36fb --- /dev/null +++ b/build.sh @@ -0,0 +1,178 @@ +#/bash/sh + +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 +tar -czvf npc_sdk.tar.gz npc_sdk.dll npc_sdk.h + +wget https://github.com/upx/upx/releases/download/v3.95/upx-3.95-amd64_linux.tar.xz +tar -xvf upx-3.95-amd64_linux.tar.xz +cp upx-3.95-amd64_linux/upx ./ + +CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go + +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 + +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 + +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 + +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 + +tar -czvf freebsd_arm_client.tar.gz npc conf/npc.conf + +CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go + +tar -czvf linux_arm_v7_client.tar.gz npc conf/npc.conf + +CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go + +tar -czvf linux_arm_v6_client.tar.gz npc conf/npc.conf + +CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go + +tar -czvf linux_arm_v5_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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go + +tar -czvf linux_arm_v5_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 GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go + +tar -czvf linux_arm_v6_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 GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go + +tar -czvf linux_arm_v7_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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +export VERSION=0.25.0 +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 +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 +docker exec -it spksrc /bin/bash -c 'cd /spksrc && make setup && cd /spksrc/spk/npc && make' +cp ~/spksrc/packages/npc_noarch-all_$VERSION-1.spk ./npc_syno.spk + + +echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin +export DOCKER_CLI_EXPERIMENTAL=enabled +docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d +docker buildx create --use --name mybuilder +docker buildx build --tag ffdfgdfg/nps:$VERSION --output type=image,push=true --file Dockerfile.nps --platform=linux/amd64,linux/arm64,linux/386,linux/arm . +docker buildx build --tag ffdfgdfg/npc:$VERSION --output type=image,push=true --file Dockerfile.npc --platform=linux/amd64,linux/arm64,linux/386,linux/arm . diff --git a/client/client.go b/client/client.go index 5bd0b01..ac300ff 100755 --- a/client/client.go +++ b/client/client.go @@ -2,18 +2,20 @@ package client import ( "bufio" + "bytes" "net" "net/http" "strconv" "time" "github.com/astaxie/beego/logs" + "github.com/xtaci/kcp-go" + "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/config" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/mux" - "github.com/xtaci/kcp-go" ) type TRPClient struct { @@ -156,7 +158,7 @@ func (s *TRPClient) newChan() { func (s *TRPClient) handleChan(src net.Conn) { lk, err := conn.NewConn(src).GetLinkInfo() - if err != nil { + if err != nil || lk == nil { src.Close() logs.Error("get connection info from server error ", err) return @@ -165,7 +167,7 @@ func (s *TRPClient) handleChan(src net.Conn) { lk.Host = common.FormatAddress(lk.Host) //if Conn type is http, read the request and log if lk.ConnType == "http" { - if targetConn, err := net.Dial(common.CONN_TCP, lk.Host); err != nil { + if targetConn, err := net.DialTimeout(common.CONN_TCP, lk.Host, lk.Option.Timeout); err != nil { logs.Warn("connect to %s error %s", lk.Host, err.Error()) src.Close() } else { @@ -188,8 +190,12 @@ func (s *TRPClient) handleChan(src net.Conn) { } return } + if lk.ConnType == "udp5" { + logs.Trace("new %s connection with the goal of %s, remote address:%s", lk.ConnType, lk.Host, lk.RemoteAddr) + s.handleUdp(src) + } //connect to target if conn type is tcp or udp - if targetConn, err := net.Dial(lk.ConnType, lk.Host); err != nil { + if targetConn, err := net.DialTimeout(lk.ConnType, lk.Host, lk.Option.Timeout); err != nil { logs.Warn("connect to %s error %s", lk.Host, err.Error()) src.Close() } else { @@ -198,6 +204,65 @@ func (s *TRPClient) handleChan(src net.Conn) { } } +func (s *TRPClient) handleUdp(serverConn net.Conn) { + // bind a local udp port + local, err := net.ListenUDP("udp", nil) + defer local.Close() + defer serverConn.Close() + if err != nil { + logs.Error("bind local udp port error ", err.Error()) + return + } + go func() { + defer serverConn.Close() + b := common.BufPoolUdp.Get().([]byte) + defer common.BufPoolUdp.Put(b) + for { + n, raddr, err := local.ReadFrom(b) + if err != nil { + logs.Error("read data from remote server error", err.Error()) + } + buf := bytes.Buffer{} + dgram := common.NewUDPDatagram(common.NewUDPHeader(0, 0, common.ToSocksAddr(raddr)), b[:n]) + dgram.Write(&buf) + b, err := conn.GetLenBytes(buf.Bytes()) + if err != nil { + logs.Warn("get len bytes error", err.Error()) + continue + } + if _, err := serverConn.Write(b); err != nil { + logs.Error("write data to remote error", err.Error()) + return + } + } + }() + b := common.BufPoolUdp.Get().([]byte) + defer common.BufPoolUdp.Put(b) + for { + n, err := serverConn.Read(b) + if err != nil { + logs.Error("read udp data from server error ", err.Error()) + return + } + + udpData, err := common.ReadUDPDatagram(bytes.NewReader(b[:n])) + if err != nil { + logs.Error("unpack data error", err.Error()) + return + } + raddr, err := net.ResolveUDPAddr("udp", udpData.Header.Addr.String()) + if err != nil { + logs.Error("build remote addr err", err.Error()) + continue // drop silently + } + _, err = local.WriteTo(udpData.Data, raddr) + if err != nil { + logs.Error("write data to remote ", raddr.String(), "error", err.Error()) + return + } + } +} + // Whether the monitor channel is closed func (s *TRPClient) ping() { s.ticker = time.NewTicker(time.Second * 5) diff --git a/client/client_test.go b/client/client_test.go deleted file mode 100644 index 84ff3b0..0000000 --- a/client/client_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package client - -import ( - "net" - "sync" - "testing" - - "github.com/cnlh/nps/lib/common" - conn2 "github.com/cnlh/nps/lib/conn" - "github.com/cnlh/nps/lib/file" -) - -func TestConfig(t *testing.T) { - conn, err := net.Dial("tcp", "127.0.0.1:8284") - if err != nil { - t.Fail() - } - c := conn2.NewConn(conn) - c.SetAlive("tcp") - if _, err := c.Write([]byte(common.Getverifyval("123"))); err != nil { - t.Fail() - } - c.WriteConfig() - config := &file.Config{ - U: "1", - P: "2", - Compress: "snappy", - Crypt: true, - CompressEncode: 0, - CompressDecode: 0, - } - host := &file.Host{ - Host: "a.o.com", - Target: "127.0.0.1:8080", - HeaderChange: "", - HostChange: "", - Flow: nil, - Client: nil, - Remark: "111", - NowIndex: 0, - TargetArr: nil, - NoStore: false, - RWMutex: sync.RWMutex{}, - } - tunnel := &file.Tunnel{ - Port: 9001, - Mode: "tcp", - Target: "127.0.0.1:8082", - Remark: "333", - } - var b []byte - if b, err = c.ReadLen(16); err != nil { - t.Fail() - } - if _, err := c.SendConfigInfo(config); err != nil { - t.Fail() - } - if !c.GetAddStatus() { - t.Fail() - } - if _, err := c.SendHostInfo(host); err != nil { - t.Fail() - } - if !c.GetAddStatus() { - t.Fail() - } - if _, err := c.SendTaskInfo(tunnel); err != nil { - t.Fail() - } - if !c.GetAddStatus() { - t.Fail() - } - c.Close() - NewRPClient("127.0.0.1:8284", string(b), "tcp").Start() -} diff --git a/client/control.go b/client/control.go index 5589d11..faf0fcb 100644 --- a/client/control.go +++ b/client/control.go @@ -220,7 +220,10 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st if _, err := c.Write([]byte(common.CONN_TEST)); err != nil { return nil, err } - if _, err := c.Write([]byte(crypt.Md5(version.GetVersion()))); err != nil { + if err := c.WriteLenContent([]byte(version.GetVersion())); err != nil { + return nil, err + } + if err := c.WriteLenContent([]byte(version.VERSION)); err != nil { return nil, err } b, err := c.GetShortContent(32) diff --git a/client/local.go b/client/local.go index 06057ca..9c903f6 100644 --- a/client/local.go +++ b/client/local.go @@ -1,8 +1,10 @@ package client import ( + "errors" "net" "net/http" + "runtime" "sync" "time" @@ -31,6 +33,14 @@ type p2pBridge struct { } func (p2pBridge *p2pBridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error) { + for i := 0; muxSession == nil; i++ { + if i >= 20 { + err = errors.New("p2pBridge:too many times to get muxSession") + logs.Error(err) + return + } + runtime.Gosched() // waiting for another goroutine establish the mux connection + } nowConn, err := muxSession.NewConn() if err != nil { udpConn = nil @@ -158,6 +168,7 @@ func handleP2PVisitor(localTcpConn net.Conn, config *config.CommonConfig, l *con if udpConn == nil { logs.Notice("new conn, P2P can not penetrate successfully, traffic will be transferred through the server") handleSecret(localTcpConn, config, l) + return } logs.Trace("start trying to connect with the server") //TODO just support compress now because there is not tls file in client packages diff --git a/cmd/npc/sdk.go b/cmd/npc/sdk.go new file mode 100644 index 0000000..cf41af9 --- /dev/null +++ b/cmd/npc/sdk.go @@ -0,0 +1,53 @@ +package main + +import "C" +import ( + "github.com/astaxie/beego/logs" + "github.com/cnlh/nps/client" + "time" +) + +func init() { + logs.SetLogger(logs.AdapterFile, `{"filename":"npc.log","daily":false,"maxlines":100000,"color":true}`) +} + +var status int +var closeBefore int +var cl *client.TRPClient + +//export StartClientByVerifyKey +func StartClientByVerifyKey(serverAddr, verifyKey, connType, proxyUrl *C.char) int { + if cl != nil { + closeBefore = 1 + cl.Close() + } + cl = client.NewRPClient(C.GoString(serverAddr), C.GoString(verifyKey), C.GoString(connType), C.GoString(proxyUrl), nil) + closeBefore = 0 + go func() { + for { + status = 1 + cl.Start() + status = 0 + if closeBefore == 1 { + return + } + time.Sleep(time.Second * 5) + } + }() + return 1 +} + +//export GetClientStatus +func GetClientStatus() int { + return status +} + +//export CloseClient +func CloseClient() { + closeBefore = 1 + cl.Close() +} + +func main() { + // Need a main function to make CGO compile package as C shared library +} diff --git a/cmd/nps/nps.go b/cmd/nps/nps.go index 22835a2..98f13af 100644 --- a/cmd/nps/nps.go +++ b/cmd/nps/nps.go @@ -18,7 +18,8 @@ import ( "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/cnlh/nps/web/routers" ) var ( @@ -29,6 +30,7 @@ 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": diff --git a/conf/nps.conf b/conf/nps.conf index c75a430..8c22ab1 100755 --- a/conf/nps.conf +++ b/conf/nps.conf @@ -41,6 +41,9 @@ web_username=admin web_password=123 web_port = 8080 web_ip=0.0.0.0 +web_base_url= +# if web under proxy use sub path. like http://host/nps need this. +#web_base_url=/nps #Web API unauthenticated IP address(the len of auth_crypt_key must be 16) auth_key=test diff --git a/go.mod b/go.mod index a540dae..a2b0199 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/panjf2000/ants/v2 v2.2.2 github.com/pkg/errors v0.8.0 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect - github.com/shirou/gopsutil v2.18.12+incompatible + 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 diff --git a/go.sum b/go.sum index 8a74eb6..428e5a8 100644 --- a/go.sum +++ b/go.sum @@ -55,6 +55,8 @@ github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI 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= @@ -89,4 +91,4 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 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= \ No newline at end of file +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index 91eeb98..96ebaec 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -6,6 +6,9 @@ import ( "encoding/json" "errors" "io" + "io/ioutil" + "net" + "strconv" "strings" ) @@ -119,7 +122,8 @@ func (Self *BasePackager) Split() (strList []string) { return } -type ConnPackager struct { // Todo +type ConnPackager struct { + // Todo ConnType uint8 BasePackager } @@ -233,3 +237,206 @@ func (Self *MuxPackager) UnPack(reader io.Reader) (n uint16, err error) { n += 5 //uint8 int32 return } + +const ( + ipV4 = 1 + domainName = 3 + ipV6 = 4 +) + +type UDPHeader struct { + Rsv uint16 + Frag uint8 + Addr *Addr +} + +func NewUDPHeader(rsv uint16, frag uint8, addr *Addr) *UDPHeader { + return &UDPHeader{ + Rsv: rsv, + Frag: frag, + Addr: addr, + } +} + +type Addr struct { + Type uint8 + Host string + Port uint16 +} + +func (addr *Addr) String() string { + return net.JoinHostPort(addr.Host, strconv.Itoa(int(addr.Port))) +} + +func (addr *Addr) Decode(b []byte) error { + addr.Type = b[0] + pos := 1 + switch addr.Type { + case ipV4: + 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() + pos += net.IPv6len + case domainName: + addrlen := int(b[pos]) + pos++ + addr.Host = string(b[pos : pos+addrlen]) + pos += addrlen + default: + return errors.New("decode error") + } + + addr.Port = binary.BigEndian.Uint16(b[pos:]) + + return nil +} + +func (addr *Addr) Encode(b []byte) (int, error) { + b[0] = addr.Type + pos := 1 + switch addr.Type { + case ipV4: + ip4 := net.ParseIP(addr.Host).To4() + if ip4 == nil { + ip4 = net.IPv4zero.To4() + } + pos += copy(b[pos:], ip4) + case domainName: + b[pos] = byte(len(addr.Host)) + pos++ + pos += copy(b[pos:], []byte(addr.Host)) + case ipV6: + ip16 := net.ParseIP(addr.Host).To16() + if ip16 == nil { + ip16 = net.IPv6zero.To16() + } + pos += copy(b[pos:], ip16) + default: + b[0] = ipV4 + copy(b[pos:pos+4], net.IPv4zero.To4()) + pos += 4 + } + binary.BigEndian.PutUint16(b[pos:], addr.Port) + pos += 2 + + return pos, nil +} + +func (h *UDPHeader) Write(w io.Writer) error { + b := BufPoolUdp.Get().([]byte) + defer BufPoolUdp.Put(b) + + binary.BigEndian.PutUint16(b[:2], h.Rsv) + b[2] = h.Frag + + addr := h.Addr + if addr == nil { + addr = &Addr{} + } + length, _ := addr.Encode(b[3:]) + + _, err := w.Write(b[:3+length]) + return err +} + +type UDPDatagram struct { + Header *UDPHeader + Data []byte +} + +func ReadUDPDatagram(r io.Reader) (*UDPDatagram, error) { + b := BufPoolUdp.Get().([]byte) + defer BufPoolUdp.Put(b) + + // when r is a streaming (such as TCP connection), we may read more than the required data, + // but we don't know how to handle it. So we use io.ReadFull to instead of io.ReadAtLeast + // to make sure that no redundant data will be discarded. + n, err := io.ReadFull(r, b[:5]) + if err != nil { + return nil, err + } + + header := &UDPHeader{ + Rsv: binary.BigEndian.Uint16(b[:2]), + Frag: b[2], + } + + atype := b[3] + hlen := 0 + switch atype { + case ipV4: + hlen = 10 + case ipV6: + hlen = 22 + case domainName: + hlen = 7 + int(b[4]) + default: + return nil, errors.New("addr not support") + } + dlen := int(header.Rsv) + if dlen == 0 { // standard SOCKS5 UDP datagram + extra, err := ioutil.ReadAll(r) // we assume no redundant data + if err != nil { + return nil, err + } + copy(b[n:], extra) + n += len(extra) // total length + dlen = n - hlen // data length + } else { // extended feature, for UDP over TCP, using reserved field as data length + if _, err := io.ReadFull(r, b[n:hlen+dlen]); err != nil { + return nil, err + } + n = hlen + dlen + } + header.Addr = new(Addr) + if err := header.Addr.Decode(b[3:hlen]); err != nil { + return nil, err + } + data := make([]byte, dlen) + copy(data, b[hlen:n]) + d := &UDPDatagram{ + Header: header, + Data: data, + } + return d, nil +} + +func NewUDPDatagram(header *UDPHeader, data []byte) *UDPDatagram { + return &UDPDatagram{ + Header: header, + Data: data, + } +} + +func (d *UDPDatagram) Write(w io.Writer) error { + h := d.Header + if h == nil { + h = &UDPHeader{} + } + buf := bytes.Buffer{} + if err := h.Write(&buf); err != nil { + return err + } + if _, err := buf.Write(d.Data); err != nil { + return err + } + + _, err := buf.WriteTo(w) + return err +} + +func ToSocksAddr(addr net.Addr) *Addr { + host := "0.0.0.0" + port := 0 + if addr != nil { + h, p, _ := net.SplitHostPort(addr.String()) + host = h + port, _ = strconv.Atoi(p) + } + return &Addr{ + Type: ipV4, + Host: host, + Port: uint16(port), + } +} diff --git a/lib/common/pool.go b/lib/common/pool.go index 1f7a47e..3ed19dc 100644 --- a/lib/common/pool.go +++ b/lib/common/pool.go @@ -7,7 +7,7 @@ import ( const PoolSize = 64 * 1024 const PoolSizeSmall = 100 -const PoolSizeUdp = 1472 +const PoolSizeUdp = 1472 + 200 const PoolSizeCopy = 32 << 10 const PoolSizeBuffer = 4096 const PoolSizeWindow = PoolSizeBuffer - 2 - 4 - 4 - 1 diff --git a/lib/common/util.go b/lib/common/util.go index 0985d00..67f58cb 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/base64" "encoding/binary" + "errors" "html/template" "io" "io/ioutil" @@ -109,8 +110,8 @@ func ChangeHostAndHeader(r *http.Request, host string, header string, addr strin } addr = strings.Split(addr, ":")[0] if prior, ok := r.Header["X-Forwarded-For"]; ok { - addr = strings.Join(prior, ", ") + ", " + addr - } + addr = strings.Join(prior, ", ") + ", " + addr + } r.Header.Set("X-Forwarded-For", addr) r.Header.Set("X-Real-IP", addr) } @@ -396,3 +397,62 @@ func GetExtFromPath(path string) string { } return string(re.Find([]byte(s[0]))) } + +var externalIp string + +func GetExternalIp() string { + if externalIp != "" { + return externalIp + } + resp, err := http.Get("http://myexternalip.com/raw") + if err != nil { + return "" + } + defer resp.Body.Close() + content, _ := ioutil.ReadAll(resp.Body) + externalIp = string(content) + return externalIp +} + +func GetIntranetIp() (error, string) { + addrs, err := net.InterfaceAddrs() + if err != nil { + return nil, "" + } + for _, address := range addrs { + // 检查ip地址判断是否回环地址 + if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { + if ipnet.IP.To4() != nil { + return nil, ipnet.IP.To4().String() + } + } + } + return errors.New("get intranet ip error"), "" +} + +func IsPublicIP(IP net.IP) bool { + if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() { + return false + } + if ip4 := IP.To4(); ip4 != nil { + switch true { + case ip4[0] == 10: + return false + case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31: + return false + case ip4[0] == 192 && ip4[1] == 168: + return false + default: + return true + } + } + return false +} + +func GetServerIpByClientIp(clientIp net.IP) string { + if IsPublicIP(clientIp) { + return GetExternalIp() + } + _, ip := GetIntranetIp() + return ip +} diff --git a/lib/conn/conn.go b/lib/conn/conn.go index 9f0c397..db03c40 100755 --- a/lib/conn/conn.go +++ b/lib/conn/conn.go @@ -87,7 +87,7 @@ func (s *Conn) GetShortContent(l int) (b []byte, err error) { //读取指定长度内容 func (s *Conn) ReadLen(cLen int, buf []byte) (int, error) { - if cLen > len(buf) { + if cLen > len(buf) || cLen <= 0 { return 0, errors.New("长度错误" + strconv.Itoa(cLen)) } if n, err := io.ReadFull(s, buf[:cLen]); err != nil || n != cLen { @@ -124,8 +124,8 @@ func (s *Conn) SetAlive(tp string) { case *net.TCPConn: conn := s.Conn.(*net.TCPConn) conn.SetReadDeadline(time.Time{}) - conn.SetKeepAlive(true) - conn.SetKeepAlivePeriod(time.Duration(2 * time.Second)) + //conn.SetKeepAlive(false) + //conn.SetKeepAlivePeriod(time.Duration(2 * time.Second)) case *mux.PortConn: s.Conn.(*mux.PortConn).SetReadDeadline(time.Time{}) } diff --git a/lib/conn/link.go b/lib/conn/link.go index 974827d..653894e 100644 --- a/lib/conn/link.go +++ b/lib/conn/link.go @@ -1,5 +1,7 @@ package conn +import "time" + type Secret struct { Password string Conn *Conn @@ -19,9 +21,20 @@ type Link struct { Compress bool LocalProxy bool RemoteAddr string + Option Options } -func NewLink(connType string, host string, crypt bool, compress bool, remoteAddr string, localProxy bool) *Link { +type Option func(*Options) + +type Options struct { + Timeout time.Duration +} + +var defaultTimeOut = time.Second * 5 + +func NewLink(connType string, host string, crypt bool, compress bool, remoteAddr string, localProxy bool, opts ...Option) *Link { + options := newOptions(opts...) + return &Link{ RemoteAddr: remoteAddr, ConnType: connType, @@ -29,5 +42,22 @@ func NewLink(connType string, host string, crypt bool, compress bool, remoteAddr Crypt: crypt, Compress: compress, LocalProxy: localProxy, + Option: options, + } +} + +func newOptions(opts ...Option) Options { + opt := Options{ + Timeout: defaultTimeOut, + } + for _, o := range opts { + o(&opt) + } + return opt +} + +func LinkTimeout(t time.Duration) Option { + return func(opt *Options) { + opt.Timeout = t } } diff --git a/lib/conn/snappy.go b/lib/conn/snappy.go index 3f22aa0..2ea1034 100644 --- a/lib/conn/snappy.go +++ b/lib/conn/snappy.go @@ -3,7 +3,6 @@ package conn import ( "io" - "github.com/cnlh/nps/lib/common" "github.com/golang/snappy" ) @@ -32,13 +31,7 @@ func (s *SnappyConn) Write(b []byte) (n int, err error) { //snappy压缩读 func (s *SnappyConn) Read(b []byte) (n int, err error) { - buf := common.BufPool.Get().([]byte) - defer common.BufPool.Put(buf) - if n, err = s.r.Read(buf); err != nil { - return - } - copy(b, buf[:n]) - return + return s.r.Read(b) } func (s *SnappyConn) Close() error { diff --git a/lib/file/obj.go b/lib/file/obj.go index 15dea37..36c783b 100644 --- a/lib/file/obj.go +++ b/lib/file/obj.go @@ -50,6 +50,7 @@ type Client struct { WebPassword string //the password of web login ConfigConnAllow bool //is allow connected by config file MaxTunnelNum int + Version string sync.RWMutex } diff --git a/lib/mux/conn.go b/lib/mux/conn.go index f665248..8f6e31f 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -499,8 +499,16 @@ start: func (Self *SendWindow) waitReceiveWindow() (err error) { t := Self.timeout.Sub(time.Now()) - if t < 0 { - t = time.Minute * 5 + if t < 0 { // not set the timeout, wait for it as long as connection close + select { + case _, ok := <-Self.setSizeCh: + if !ok { + return errors.New("conn.writeWindow: window closed") + } + return nil + case <-Self.closeOpCh: + return errors.New("conn.writeWindow: window closed") + } } timer := time.NewTimer(t) defer timer.Stop() diff --git a/lib/mux/queue.go b/lib/mux/queue.go index 6f14faa..9a62fa2 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -218,7 +218,7 @@ type ReceiveWindowQueue struct { // On ARM, x86-32, and 32-bit MIPS, it is the caller's responsibility // to arrange for 64-bit alignment of 64-bit words accessed atomically. // The first word in a variable or in an allocated struct, array, or slice can be relied upon to be 64-bit aligned. - timeout time.Time + timeout time.Time } func (Self *ReceiveWindowQueue) New() { @@ -300,8 +300,14 @@ func (Self *ReceiveWindowQueue) waitPush() (err error) { //logs.Warn("wait push") //defer logs.Warn("wait push finish") t := Self.timeout.Sub(time.Now()) - if t <= 0 { - t = time.Minute * 5 + if t <= 0 { // not set the timeout, so wait for it without timeout, just like a tcp connection + select { + case <-Self.readOp: + return nil + case <-Self.stopOp: + err = io.EOF + return + } } timer := time.NewTimer(t) defer timer.Stop() diff --git a/lib/version/version.go b/lib/version/version.go index 1f14ef1..c46c010 100644 --- a/lib/version/version.go +++ b/lib/version/version.go @@ -1,8 +1,8 @@ package version -const VERSION = "0.24.0" +const VERSION = "0.25.0" // Compulsory minimum version, Minimum downward compatibility to this version func GetVersion() string { - return "0.24.0" + return "0.25.0" } diff --git a/server/proxy/http.go b/server/proxy/http.go index 31ec81c..936aae3 100644 --- a/server/proxy/http.go +++ b/server/proxy/http.go @@ -171,11 +171,11 @@ reset: } }() for { - if resp, err := http.ReadResponse(bufio.NewReader(connClient), r); err != nil { + if resp, err := http.ReadResponse(bufio.NewReader(connClient), r); err != nil || resp == nil { return } else { //if the cache is start and the response is in the extension,store the response to the cache list - if s.useCache && strings.Contains(r.URL.Path, ".") { + if s.useCache && r.URL != nil && strings.Contains(r.URL.Path, ".") { b, err := httputil.DumpResponse(resp, true) if err != nil { return diff --git a/server/proxy/socks5.go b/server/proxy/socks5.go index d79be72..dd27dfd 100755 --- a/server/proxy/socks5.go +++ b/server/proxy/socks5.go @@ -154,27 +154,129 @@ func (s *Sock5ModeServer) handleConnect(c net.Conn) { // passive mode func (s *Sock5ModeServer) handleBind(c net.Conn) { } +func (s *Sock5ModeServer) sendUdpReply(writeConn net.Conn, c net.Conn, rep uint8, serverIp string) { + reply := []byte{ + 5, + rep, + 0, + 1, + } + localHost, localPort, _ := net.SplitHostPort(c.LocalAddr().String()) + localHost = serverIp + ipBytes := net.ParseIP(localHost).To4() + nPort, _ := strconv.Atoi(localPort) + reply = append(reply, ipBytes...) + portBytes := make([]byte, 2) + binary.BigEndian.PutUint16(portBytes, uint16(nPort)) + reply = append(reply, portBytes...) + writeConn.Write(reply) + +} -//udp func (s *Sock5ModeServer) handleUDP(c net.Conn) { - /* - +----+------+------+----------+----------+----------+ - |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | - +----+------+------+----------+----------+----------+ - | 2 | 1 | 1 | Variable | 2 | Variable | - +----+------+------+----------+----------+----------+ - */ - buf := make([]byte, 3) - c.Read(buf) - // relay udp datagram silently, without any notification to the requesting client - if buf[2] != 0 { - // does not support fragmentation, drop it - logs.Warn("does not support fragmentation, drop") - dummy := make([]byte, maxUDPPacketSize) - c.Read(dummy) + defer c.Close() + addrType := make([]byte, 1) + c.Read(addrType) + var host string + switch addrType[0] { + case ipV4: + ipv4 := make(net.IP, net.IPv4len) + c.Read(ipv4) + host = ipv4.String() + case ipV6: + ipv6 := make(net.IP, net.IPv6len) + c.Read(ipv6) + host = ipv6.String() + case domainName: + var domainLen uint8 + binary.Read(c, binary.BigEndian, &domainLen) + domain := make([]byte, domainLen) + c.Read(domain) + host = string(domain) + default: + s.sendReply(c, addrTypeNotSupported) + return + } + //读取端口 + var port uint16 + binary.Read(c, binary.BigEndian, &port) + logs.Warn(host, string(port)) + replyAddr, err := net.ResolveUDPAddr("udp", s.task.ServerIp+":0") + if err != nil { + logs.Error("build local reply addr error", err) + return + } + reply, err := net.ListenUDP("udp", replyAddr) + if err != nil { + s.sendReply(c, addrTypeNotSupported) + logs.Error("listen local reply udp port error") + return + } + // reply the local addr + s.sendUdpReply(c, reply, succeeded, common.GetServerIpByClientIp(c.RemoteAddr().(*net.TCPAddr).IP)) + defer reply.Close() + // new a tunnel to client + link := conn.NewLink("udp5", "", s.task.Client.Cnf.Crypt, s.task.Client.Cnf.Compress, c.RemoteAddr().String(), false) + target, err := s.bridge.SendLinkInfo(s.task.Client.Id, link, s.task) + if err != nil { + logs.Warn("get connection from client id %d error %s", s.task.Client.Id, err.Error()) + return } - s.doConnect(c, associateMethod) + var clientAddr net.Addr + // copy buffer + go func() { + b := common.BufPoolUdp.Get().([]byte) + defer common.BufPoolUdp.Put(b) + defer c.Close() + + for { + n, laddr, err := reply.ReadFrom(b) + if err != nil { + logs.Error("read data from %s err %s", reply.LocalAddr().String(), err.Error()) + return + } + if clientAddr == nil { + clientAddr = laddr + } + if _, err := target.Write(b[:n]); err != nil { + logs.Error("write data to client error", err.Error()) + return + } + } + }() + + go func() { + var l int32 + b := common.BufPoolUdp.Get().([]byte) + defer common.BufPoolUdp.Put(b) + defer c.Close() + for { + if err := binary.Read(target, binary.LittleEndian, &l); err != nil || l >= common.PoolSizeUdp || l <= 0 { + logs.Warn("read len bytes error", err.Error()) + return + } + binary.Read(target, binary.LittleEndian, b[:l]) + if err != nil { + logs.Warn("read data form client error", err.Error()) + return + } + if _, err := reply.WriteTo(b[:l], clientAddr); err != nil { + logs.Warn("write data to user ", err.Error()) + return + } + } + }() + + b := common.BufPoolUdp.Get().([]byte) + defer common.BufPoolUdp.Put(b) + for { + _, err := c.Read(b) + if err != nil { + c.Close() + return + } + } } //new conn diff --git a/server/proxy/tcp.go b/server/proxy/tcp.go index cb7bc94..5b04252 100755 --- a/server/proxy/tcp.go +++ b/server/proxy/tcp.go @@ -63,7 +63,7 @@ func (s *WebServer) Start() error { <-stop } beego.BConfig.WebConfig.Session.SessionOn = true - beego.SetStaticPath("/static", filepath.Join(common.GetRunPath(), "web", "static")) + 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 { beego.InitBeforeHTTPRun() diff --git a/server/server.go b/server/server.go index 911fde5..5335a40 100644 --- a/server/server.go +++ b/server/server.go @@ -2,6 +2,7 @@ package server import ( "errors" + "github.com/cnlh/nps/lib/version" "math" "os" "strconv" @@ -271,8 +272,9 @@ func GetClientList(start, length int, search, sort, order string, clientId int) func dealClientData() { file.GetDb().JsonDb.Clients.Range(func(key, value interface{}) bool { v := value.(*file.Client) - if _, ok := Bridge.Client.Load(v.Id); ok { + if vv, ok := Bridge.Client.Load(v.Id); ok { v.IsConnect = true + v.Version = vv.(*bridge.Client).Version } else { v.IsConnect = false } @@ -338,6 +340,7 @@ func DelClientConnect(clientId int) { func GetDashboardData() map[string]interface{} { data := make(map[string]interface{}) + data["version"] = version.VERSION data["hostCount"] = common.GeSynctMapLen(file.GetDb().JsonDb.Hosts) data["clientCount"] = common.GeSynctMapLen(file.GetDb().JsonDb.Clients) - 1 //Remove the public key client dealClientData() diff --git a/update.sh b/update.sh new file mode 100644 index 0000000..3e0bfe3 --- /dev/null +++ b/update.sh @@ -0,0 +1,50 @@ +#/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/base.go b/web/controllers/base.go index b608478..1ba5a07 100755 --- a/web/controllers/base.go +++ b/web/controllers/base.go @@ -22,6 +22,7 @@ type BaseController struct { //初始化参数 func (s *BaseController) Prepare() { + s.Data["web_base_url"] = beego.AppConfig.String("web_base_url") controllerName, actionName := s.GetControllerAndAction() s.controllerName = strings.ToLower(controllerName[0 : len(controllerName)-10]) s.actionName = strings.ToLower(actionName) @@ -34,7 +35,7 @@ func (s *BaseController) Prepare() { timeNowUnix := time.Now().Unix() if !((math.Abs(float64(timeNowUnix-int64(timestamp))) <= 20) && (crypt.Md5(configKey+strconv.Itoa(timestamp)) == md5Key)) { if s.GetSession("auth") != true { - s.Redirect("/login/index", 302) + s.Redirect(beego.AppConfig.String("web_base_url")+"/login/index", 302) } } if s.GetSession("isAdmin") != nil && !s.GetSession("isAdmin").(bool) { @@ -60,6 +61,7 @@ func (s *BaseController) Prepare() { //加载模板 func (s *BaseController) display(tpl ...string) { + s.Data["web_base_url"] = beego.AppConfig.String("web_base_url") var tplname string if s.Data["menu"] == nil { s.Data["menu"] = s.actionName @@ -83,6 +85,7 @@ func (s *BaseController) display(tpl ...string) { //错误 func (s *BaseController) error() { + s.Data["web_base_url"] = beego.AppConfig.String("web_base_url") s.Layout = "public/layout.html" s.TplName = "public/error.html" } diff --git a/web/controllers/index.go b/web/controllers/index.go index 5ecdb15..5b60495 100755 --- a/web/controllers/index.go +++ b/web/controllers/index.go @@ -4,6 +4,8 @@ import ( "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/server" "github.com/cnlh/nps/server/tool" + + "github.com/astaxie/beego" ) type IndexController struct { @@ -11,6 +13,7 @@ type IndexController struct { } func (s *IndexController) Index() { + s.Data["web_base_url"] = beego.AppConfig.String("web_base_url") s.Data["data"] = server.GetDashboardData() s.SetInfo("dashboard") s.display("index/index") diff --git a/web/controllers/login.go b/web/controllers/login.go index 64873a4..a460b75 100755 --- a/web/controllers/login.go +++ b/web/controllers/login.go @@ -14,6 +14,7 @@ type LoginController struct { } 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" } @@ -60,6 +61,7 @@ func (self *LoginController) Verify() { } func (self *LoginController) Register() { if self.Ctx.Request.Method == "GET" { + self.Data["web_base_url"] = beego.AppConfig.String("web_base_url") self.TplName = "login/register.html" } else { if b, err := beego.AppConfig.Bool("allow_user_register"); err != nil || !b { @@ -91,5 +93,5 @@ func (self *LoginController) Register() { func (self *LoginController) Out() { self.SetSession("auth", false) - self.Redirect("/login/index", 302) + self.Redirect(beego.AppConfig.String("web_base_url")+"/login/index", 302) } diff --git a/web/routers/router.go b/web/routers/router.go index f86facf..31221eb 100755 --- a/web/routers/router.go +++ b/web/routers/router.go @@ -5,10 +5,22 @@ import ( "github.com/cnlh/nps/web/controllers" ) -func init() { - beego.Router("/", &controllers.IndexController{}, "*:Index") - beego.AutoRouter(&controllers.IndexController{}) - beego.AutoRouter(&controllers.LoginController{}) - beego.AutoRouter(&controllers.ClientController{}) - beego.AutoRouter(&controllers.AuthController{}) +func Init() { + web_base_url := beego.AppConfig.String("web_base_url") + if len(web_base_url) > 0 { + ns := beego.NewNamespace(web_base_url, + beego.NSRouter("/", &controllers.IndexController{}, "*:Index"), + beego.NSAutoRouter(&controllers.IndexController{}), + beego.NSAutoRouter(&controllers.LoginController{}), + beego.NSAutoRouter(&controllers.ClientController{}), + beego.NSAutoRouter(&controllers.AuthController{}), + ) + beego.AddNamespace(ns) + } else { + beego.Router("/", &controllers.IndexController{}, "*:Index") + beego.AutoRouter(&controllers.IndexController{}) + beego.AutoRouter(&controllers.LoginController{}) + beego.AutoRouter(&controllers.ClientController{}) + beego.AutoRouter(&controllers.AuthController{}) + } } diff --git a/web/static/js/langchange.js b/web/static/js/langchange.js index 54961d7..e7a60fb 100644 --- a/web/static/js/langchange.js +++ b/web/static/js/langchange.js @@ -12,7 +12,7 @@ $.ajax({ type: "GET", - url: defaults.file, + url: window.nps.web_base_url + defaults.file, dataType: "xml", success: function (xml) { $(xml).find('text').each(function () { @@ -65,4 +65,4 @@ $(document).ready(function () { setCookie("lang", "zh") $("body").cloudLang({lang: "zh", file: "/static/page/lang-example.xml"}); }); -}); \ No newline at end of file +}); diff --git a/web/views/client/add.html b/web/views/client/add.html index 07719bd..30563c2 100755 --- a/web/views/client/add.html +++ b/web/views/client/add.html @@ -134,7 +134,7 @@ $("#add").on("click", function () { $.ajax({ type: "POST", - url: "/client/add", + url: "{{.web_base_url}}/client/add", data: $("form").serializeArray(), success: function (res) { alert(res.msg) diff --git a/web/views/client/edit.html b/web/views/client/edit.html index 20db215..0ae06a2 100755 --- a/web/views/client/edit.html +++ b/web/views/client/edit.html @@ -145,7 +145,7 @@ $("#add").on("click", function () { $.ajax({ type: "POST", - url: "/client/edit", + url: "{{.web_base_url}}/client/edit", data: $("form").serializeArray(), success: function (res) { alert(res.msg) diff --git a/web/views/client/list.html b/web/views/client/list.html index ce49bfe..d0d3e6f 100755 --- a/web/views/client/list.html +++ b/web/views/client/list.html @@ -20,7 +20,7 @@
- 新增 + 新增
@@ -42,7 +42,7 @@ if (confirm("Are you sure you want to delete it??")) { $.ajax({ type: "POST", - url: "/client/del", + url: "{{.web_base_url}}/client/del", data: {"id": id}, success: function (res) { alert(res.msg) @@ -58,7 +58,7 @@ if (confirm("Are you sure you want to start it??")) { $.ajax({ type: "POST", - url: "/client/changestatus", + url: "{{.web_base_url}}/client/changestatus", data: {"id": id, "status": 1}, success: function (res) { alert(res.msg) @@ -74,7 +74,7 @@ if (confirm("Are you sure you want to stop it?")) { $.ajax({ type: "POST", - url: "/client/changestatus", + url: "{{.web_base_url}}/client/changestatus", data: { "id": id, "status": 0 }, @@ -90,26 +90,26 @@ } function edit(id) { - window.location.href = "/client/edit?id=" + id + window.location.href = "{{.web_base_url}}/client/edit?id=" + id } function add() { - window.location.href = "/client/add" + window.location.href = "{{.web_base_url}}/client/add" } function tunnel(id) { - window.location.href = "/index/all?client_id=" + id + window.location.href = "{{.web_base_url}}/index/all?client_id=" + id } function host(id) { - window.location.href = "/index/hostlist?client_id=" + id + window.location.href = "{{.web_base_url}}/index/hostlist?client_id=" + id } /*bootstrap table*/ $('#table').bootstrapTable({ toolbar: "#toolbar", method: 'post', // 服务器数据的请求方式 get or post - url: "/client/list", // 服务器数据的加载地址 + url: "{{.web_base_url}}/client/list", // 服务器数据的加载地址 contentType: "application/x-www-form-urlencoded", striped: true, // 设置为true会有隔行变色效果 search: true, @@ -150,6 +150,11 @@ title: 'remark',//标题 visible: true,//false表示不显示 }, + { + field: 'Version',//域值 + title: 'version',//标题 + visible: true,//false表示不显示 + }, { field: 'VerifyKey',//域值 title: 'vkey',//标题 diff --git a/web/views/index/add.html b/web/views/index/add.html index c2208a7..302553a 100755 --- a/web/views/index/add.html +++ b/web/views/index/add.html @@ -162,7 +162,7 @@ $("#add").on("click", function () { $.ajax({ type: "POST", - url: "/index/add", + url: "{{.web_base_url}}/index/add", data: $("form").serializeArray(), success: function (res) { alert(res.msg) diff --git a/web/views/index/edit.html b/web/views/index/edit.html index ef48ad0..32e3c3f 100755 --- a/web/views/index/edit.html +++ b/web/views/index/edit.html @@ -160,7 +160,7 @@ $("#add").on("click", function () { $.ajax({ type: "POST", - url: "/index/edit", + url: "{{.web_base_url}}/index/edit", data: $("form").serializeArray(), success: function (res) { alert(res.msg) diff --git a/web/views/index/hadd.html b/web/views/index/hadd.html index ac2a5cc..1a4482d 100755 --- a/web/views/index/hadd.html +++ b/web/views/index/hadd.html @@ -112,7 +112,7 @@ $("#add").on("click", function () { $.ajax({ type: "POST", - url: "/index/addhost", + url: "{{.web_base_url}}/index/addhost", data: $("form").serializeArray(), success: function (res) { alert(res.msg) diff --git a/web/views/index/hedit.html b/web/views/index/hedit.html index 5b430e9..9e17f45 100644 --- a/web/views/index/hedit.html +++ b/web/views/index/hedit.html @@ -116,7 +116,7 @@ $("#add").on("click", function () { $.ajax({ type: "POST", - url: "/index/edithost", + url: "{{.web_base_url}}/index/edithost", data: $("form").serializeArray(), success: function (res) { alert(res.msg) diff --git a/web/views/index/hlist.html b/web/views/index/hlist.html index 6d2ccaa..d2ec24e 100755 --- a/web/views/index/hlist.html +++ b/web/views/index/hlist.html @@ -18,7 +18,7 @@
- 新增
@@ -158,7 +158,7 @@ if (confirm("Are you sure you want to delete it??")) { $.ajax({ type: "POST", - url: "/index/delhost", + url: "{{.web_base_url}}/index/delhost", data: {"id": id}, success: function (res) { alert(res.msg) @@ -171,7 +171,7 @@ } function edit(id) { - window.location.href = "/index/edithost?id=" + id + window.location.href = "{{.web_base_url}}/index/edithost?id=" + id } diff --git a/web/views/index/index.html b/web/views/index/index.html index d331443..2d86939 100755 --- a/web/views/index/index.html +++ b/web/views/index/index.html @@ -142,6 +142,16 @@
+
  • +
    +
    + 服务端版本 +
    +
    + {{.data.version}} +
    +
    +
  • @@ -754,4 +764,4 @@ this.myChart7.resize(); }); - \ No newline at end of file + diff --git a/web/views/index/list.html b/web/views/index/list.html index 5537f67..248d2cb 100755 --- a/web/views/index/list.html +++ b/web/views/index/list.html @@ -18,7 +18,7 @@
    - 新增
    diff --git a/web/views/login/index.html b/web/views/login/index.html index a28ae87..ffe89d0 100755 --- a/web/views/login/index.html +++ b/web/views/login/index.html @@ -8,10 +8,10 @@ nps admin login - - + + - + @@ -49,7 +49,7 @@ {{if eq true .register_allow}} - register + register {{end}} @@ -59,7 +59,7 @@ - + @@ -68,11 +68,11 @@ function login() { $.ajax({ type: "POST", - url: "/login/verify", + url: "{{.web_base_url}}/login/verify", data: $("form").serializeArray(), success: function (res) { if (res.status) { - window.location.href = "/index/index" + window.location.href = "{{.web_base_url}}/index/index" } else { alert(res.msg) } diff --git a/web/views/login/register.html b/web/views/login/register.html index 88d6e3b..a67e8c5 100644 --- a/web/views/login/register.html +++ b/web/views/login/register.html @@ -8,10 +8,10 @@ nps register - - + + - + @@ -34,22 +34,22 @@ - login + login - + + + + + - - - + + + - + - - + + - + @@ -35,7 +35,7 @@ @@ -115,7 +115,7 @@
  • - + logout
  • @@ -142,6 +142,9 @@