diff --git a/README.md b/README.md
index 9d679391..5fb13c63 100644
--- a/README.md
+++ b/README.md
@@ -247,23 +247,22 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务
**适用范围:** 大流量传输场景,流量不经过公网服务器,但是由于p2p穿透和nat类型关系较大,不保证100%成功,支持大部分nat类型。[nat类型检测](#nat类型检测)
**假设场景:**
-内网1机器ip为10.1.50.2 内网2机器2 ip为10.2.50.2
-想通过访问内网1机器1的2000端口---->访问到内网2机器3 10.2.50.3的22端口
+想通过访问使用端机器(访问端,也就是本机)的2000端口---->访问到内网机器 10.2.50.2的22端口
**使用步骤**
- 在`nps.conf`中设置`p2p_ip`(nps服务器ip)和`p2p_port`(nps服务器udp端口)
- 在刚才刚才创建的客户端中添加一条p2p代理,并设置唯一密钥p2pssh
-- 在机器1执行命令
+- 在使用端机器(本机)执行命令
```
-./npc -server=1.1.1.1:8284 -vkey=123 -password=p2pssh -target=10.2.50.3:22
+./npc -server=1.1.1.1:8284 -vkey=123 -password=p2pssh -target=10.2.50.2:22
```
如需指定本地端口可加参数`-local_port=xx`,默认为2000
**注意:** password为web管理上添加的唯一密钥,具体命令可查看web管理上的命令提示
-假设机器3用户名为root,现在在机器1上执行`ssh -p 2000 root@127.0.0.1`即可访问机器2的ssh
+假设内网机器为10.2.50.2的ssh用户名为root,现在在本机上执行`ssh -p 2000 root@127.0.0.1`即可访问机器2的ssh,如果是网站在浏览器访问127.0.0.1:2000端口即可。
@@ -1040,6 +1039,13 @@ POST /auth/getauthkey
## 捐助
如果您觉得nps对你有帮助,欢迎给予我们一定捐助,也是帮助nps更好的发展。
+## 致谢
+Thanks [jetbrains](https://www.jetbrains.com/?from=nps) for providing development tools for nps
+
+
+
+
+
### 支付宝

diff --git a/build.sh b/build.sh
index 1df36fba..df967c41 100644
--- a/build.sh
+++ b/build.sh
@@ -1,4 +1,5 @@
#/bash/sh
+export VERSION=0.25.1
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
@@ -10,75 +11,75 @@ 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
+tar -czvf linux_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.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
+tar -czvf linux_386_client.tar.gz npc conf/npc.conf conf/multi_account.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
+tar -czvf freebsd_386_client.tar.gz npc conf/npc.conf conf/multi_account.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
+tar -czvf freebsd_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.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
+tar -czvf freebsd_arm_client.tar.gz npc conf/npc.conf conf/multi_account.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
+tar -czvf linux_arm_v7_client.tar.gz npc conf/npc.conf conf/multi_account.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
+tar -czvf linux_arm_v6_client.tar.gz npc conf/npc.conf conf/multi_account.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
+tar -czvf linux_arm_v5_client.tar.gz npc conf/npc.conf conf/multi_account.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
+tar -czvf linux_arm64_client.tar.gz npc conf/npc.conf conf/multi_account.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
+tar -czvf linux_mips64_client.tar.gz npc conf/npc.conf conf/multi_account.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
+tar -czvf linux_mips64le_client.tar.gz npc conf/npc.conf conf/multi_account.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
+tar -czvf linux_mipsle_client.tar.gz npc conf/npc.conf conf/multi_account.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
+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
+tar -czvf win_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
+tar -czvf win_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
+tar -czvf macos_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
@@ -157,7 +158,6 @@ CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -stat
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
diff --git a/client/client.go b/client/client.go
index ac300ffe..7a6f1da1 100755
--- a/client/client.go
+++ b/client/client.go
@@ -42,12 +42,19 @@ func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl st
}
}
+var NowStatus int
+var CloseClient bool
//start
func (s *TRPClient) Start() {
+ CloseClient = false
retry:
+ if CloseClient {
+ return
+ }
+ NowStatus = 0
c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN, s.proxyUrl)
if err != nil {
- logs.Error("The connection server failed and will be reconnected in five seconds")
+ logs.Error("The connection server failed and will be reconnected in five seconds, error", err.Error())
time.Sleep(time.Second * 5)
goto retry
}
@@ -66,6 +73,7 @@ retry:
if s.cnf != nil && len(s.cnf.Healths) > 0 {
go heathCheck(s.cnf.Healths, s.signal)
}
+ NowStatus = 1
//msg connection, eg udp
s.handleMain()
}
@@ -279,6 +287,8 @@ loop:
}
func (s *TRPClient) Close() {
+ CloseClient = true
+ NowStatus = 0
if s.tunnel != nil {
s.tunnel.Close()
}
diff --git a/client/control.go b/client/control.go
index faf0fcbd..d8b98f32 100644
--- a/client/control.go
+++ b/client/control.go
@@ -198,7 +198,7 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st
return nil, er
}
connection, err = n.Dial("tcp", server)
- case "http":
+ default:
connection, err = NewHttpProxyConn(u, server)
}
} else {
@@ -241,8 +241,7 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st
if s, err := c.ReadFlag(); err != nil {
return nil, err
} else if s == common.VERIFY_EER {
- logs.Error("Validation key %s incorrect", vkey)
- os.Exit(0)
+ return nil, errors.New(fmt.Sprintf("Validation key %s incorrect", vkey))
}
if _, err := c.Write([]byte(connType)); err != nil {
return nil, err
@@ -262,7 +261,7 @@ func NewHttpProxyConn(url *url.URL, remoteAddr string) (net.Conn, error) {
Proto: "HTTP/1.1",
}
password, _ := url.User.Password()
- req.Header.Set("Proxy-Authorization", "Basic "+basicAuth(url.User.Username(), password))
+ req.Header.Set("Authorization", "Basic "+basicAuth(strings.Trim(url.User.Username(), " "), password))
b, err := httputil.DumpRequest(req, false)
if err != nil {
return nil, err
diff --git a/cmd/npc/sdk.go b/cmd/npc/sdk.go
index cf41af96..b8cc38f5 100644
--- a/cmd/npc/sdk.go
+++ b/cmd/npc/sdk.go
@@ -1,51 +1,49 @@
package main
-import "C"
import (
+ "C"
"github.com/astaxie/beego/logs"
"github.com/cnlh/nps/client"
- "time"
+ "github.com/cnlh/nps/lib/common"
+ "github.com/cnlh/nps/lib/version"
)
-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 {
+ logs.SetLogger("store")
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)
- }
+ cl.Start()
+ return
}()
return 1
}
//export GetClientStatus
func GetClientStatus() int {
- return status
+ return client.NowStatus
}
//export CloseClient
func CloseClient() {
- closeBefore = 1
- cl.Close()
+ if cl != nil {
+ cl.Close()
+ }
+}
+
+//export Version
+func Version() *C.char {
+ return C.CString(version.VERSION)
+}
+
+//export Logs
+func Logs() *C.char {
+ return C.CString(common.GetLogMsg())
}
func main() {
diff --git a/lib/common/logs.go b/lib/common/logs.go
new file mode 100644
index 00000000..477ac5b3
--- /dev/null
+++ b/lib/common/logs.go
@@ -0,0 +1,48 @@
+package common
+
+import (
+ "github.com/astaxie/beego/logs"
+ "time"
+)
+
+const MaxMsgLen = 5000
+
+var logMsgs string
+
+func init() {
+ logs.Register("store", func() logs.Logger {
+ return new(StoreMsg)
+ })
+}
+
+func GetLogMsg() string {
+ return logMsgs
+}
+
+type StoreMsg struct {
+}
+
+func (lg *StoreMsg) Init(config string) error {
+ return nil
+}
+
+func (lg *StoreMsg) WriteMsg(when time.Time, msg string, level int) error {
+ m := when.Format("2006-01-02 15:04:05") + " " + msg + "\r\n"
+ if len(logMsgs) > MaxMsgLen {
+ start := MaxMsgLen - len(m)
+ if start <= 0 {
+ start = MaxMsgLen
+ }
+ logMsgs = logMsgs[start:]
+ }
+ logMsgs += m
+ return nil
+}
+
+func (lg *StoreMsg) Destroy() {
+ return
+}
+
+func (lg *StoreMsg) Flush() {
+ return
+}
diff --git a/lib/config/config.go b/lib/config/config.go
index 89a6bfd4..96531e2f 100644
--- a/lib/config/config.go
+++ b/lib/config/config.go
@@ -241,13 +241,15 @@ func dealTunnel(s string) *file.Tunnel {
t.StripPre = item[1]
case "multi_account":
t.MultiAccount = &file.MultiAccount{}
- if b, err := common.ReadAllFromFile(item[1]); err != nil {
- panic(err)
- } else {
- if content, err := common.ParseStr(string(b)); err != nil {
+ if common.FileExists(item[1]){
+ if b, err := common.ReadAllFromFile(item[1]); err != nil {
panic(err)
} else {
- t.MultiAccount.AccountMap = dealMultiUser(content)
+ if content, err := common.ParseStr(string(b)); err != nil {
+ panic(err)
+ } else {
+ t.MultiAccount.AccountMap = dealMultiUser(content)
+ }
}
}
}
diff --git a/lib/install/install.go b/lib/install/install.go
index 24af9b94..7b035814 100644
--- a/lib/install/install.go
+++ b/lib/install/install.go
@@ -62,11 +62,22 @@ WantedBy=multi-user.target`
log.Println("Executable files have been copied to", "/usr/bin/nps")
}
systemd := unit + "\n\n" + service + "\n\n" + install
- _ = 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)
+ 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)
}
log.Println("install ok!")
diff --git a/lib/mux/pconn.go b/lib/mux/pconn.go
index b351e7cf..35af3ccb 100644
--- a/lib/mux/pconn.go
+++ b/lib/mux/pconn.go
@@ -6,15 +6,17 @@ import (
)
type PortConn struct {
- Conn net.Conn
- rs []byte
- start int
+ Conn net.Conn
+ rs []byte
+ readMore bool
+ start int
}
-func newPortConn(conn net.Conn, rs []byte) *PortConn {
+func newPortConn(conn net.Conn, rs []byte, readMore bool) *PortConn {
return &PortConn{
- Conn: conn,
- rs: rs,
+ Conn: conn,
+ rs: rs,
+ readMore: readMore,
}
}
@@ -29,9 +31,15 @@ func (pConn *PortConn) Read(b []byte) (n int, err error) {
defer func() {
pConn.start = len(pConn.rs)
}()
- return copy(b, pConn.rs[pConn.start:]), nil
+ n = copy(b, pConn.rs[pConn.start:])
+ if !pConn.readMore {
+ return
+ }
}
- return pConn.Conn.Read(b)
+ var n2 = 0
+ n2, err = pConn.Conn.Read(b[n:])
+ n = n + n2
+ return
}
func (pConn *PortConn) Write(b []byte) (n int, err error) {
diff --git a/lib/mux/pmux.go b/lib/mux/pmux.go
index e593bb07..f4e9d4a3 100644
--- a/lib/mux/pmux.go
+++ b/lib/mux/pmux.go
@@ -89,6 +89,7 @@ func (pMux *PortMux) process(conn net.Conn) {
var ch chan *PortConn
var rs []byte
var buffer bytes.Buffer
+ var readMore = false
switch common.BytesToNum(buf) {
case HTTP_CONNECT, HTTP_DELETE, HTTP_GET, HTTP_HEAD, HTTP_OPTIONS, HTTP_POST, HTTP_PUT, HTTP_TRACE: //http and manager
buffer.Reset()
@@ -123,6 +124,7 @@ func (pMux *PortMux) process(conn net.Conn) {
case CLIENT: // client connection
ch = pMux.clientConn
default: // https
+ readMore = true
ch = pMux.httpsConn
}
if len(rs) == 0 {
@@ -131,7 +133,7 @@ func (pMux *PortMux) process(conn net.Conn) {
timer := time.NewTimer(ACCEPT_TIME_OUT)
select {
case <-timer.C:
- case ch <- newPortConn(conn, rs):
+ case ch <- newPortConn(conn, rs, readMore):
}
}
diff --git a/lib/version/version.go b/lib/version/version.go
index c46c0102..b3ffbb1b 100644
--- a/lib/version/version.go
+++ b/lib/version/version.go
@@ -1,6 +1,6 @@
package version
-const VERSION = "0.25.0"
+const VERSION = "0.25.1"
// Compulsory minimum version, Minimum downward compatibility to this version
func GetVersion() string {
diff --git a/server/server.go b/server/server.go
index 5335a400..868a94da 100644
--- a/server/server.go
+++ b/server/server.go
@@ -342,7 +342,10 @@ 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
+ data["clientCount"] = common.GeSynctMapLen(file.GetDb().JsonDb.Clients)
+ if beego.AppConfig.String("public_vkey") != "" { //remove public vkey
+ data["clientCount"] = data["clientCount"].(int) - 1
+ }
dealClientData()
c := 0
var in, out int64
diff --git a/server/tool/utils.go b/server/tool/utils.go
index 6a58bab8..fb8fa55e 100644
--- a/server/tool/utils.go
+++ b/server/tool/utils.go
@@ -31,6 +31,9 @@ func InitAllowPort() {
}
func TestServerPort(p int, m string) (b bool) {
+ if m == "p2p" || m == "secret" {
+ return true
+ }
if p > 65535 || p < 0 {
return false
}
diff --git a/web/controllers/login.go b/web/controllers/login.go
index a460b751..10da8d7e 100755
--- a/web/controllers/login.go
+++ b/web/controllers/login.go
@@ -22,6 +22,8 @@ func (self *LoginController) Verify() {
var auth bool
if self.GetString("password") == beego.AppConfig.String("web_password") && self.GetString("username") == beego.AppConfig.String("web_username") {
self.SetSession("isAdmin", true)
+ self.DelSession("clientId")
+ self.DelSession("username")
auth = true
server.Bridge.Register.Store(common.GetIpByAddr(self.Ctx.Input.IP()), time.Now().Add(time.Hour*time.Duration(2)))
}
diff --git a/web/static/page/lang-example.xml b/web/static/page/lang-example.xml
new file mode 100644
index 00000000..1858935f
--- /dev/null
+++ b/web/static/page/lang-example.xml
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 流量限制
+ flow limit
+
+
+ 带宽限制
+ bandwidth
+
+
+ 最大连接数限制
+ maximum number of client connections
+
+
+
+ basic权限验证用户名
+ web authentication username
+
+
+ basic权限验证密码
+ web authentication password
+
+
+ 客户端连接密钥
+ client connection key
+
+
+ 压缩
+ compress
+
+
+ 加密
+ crypt
+
+
+
+
+ 域名
+ host
+
+
+ 协议类型
+ scheme
+
+
+ url路由
+ url router
+
+
+ 客户端id
+ client id
+
+
+ 内网目标(ip:端口)
+ target of Intranet(ip:port)
+
+
+
+ request host修改
+ host modify
+
+
+
+
+ 隧道类型
+ mode
+
+
+ 服务端端口
+ server port
+
+
+ 服务端端口
+ server ip
+
+
+ 加密
+ crypt
+
+
+ 本地路径
+ local path
+
+
+ 访问前缀
+ strip pre
+
+
+ 唯一识别密钥
+ unique vkey
+
+
+
+
+ 新增
+ add
+
+
+
+ 当前连接数
+ now conn num
+
+
+ export flow
+
+
+ inlet flow
+
+
+ command
+
+
+ allow client connect by config file
+
+
+ username of web login
+
+
+ password of web login
+
+
+ https cert file path
+
+
+ https key file path
+
+
+
+ max tunnel num
+
+
+
+ Is the proxy local to the server?
+
+
+
+
+ save
+
+
+
+