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 + + + + + ### 支付宝 ![image](https://github.com/cnlh/nps/blob/master/image/donation_zfb.png?raw=true) 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 @@ + + + 仪表盘 + dashboard + + + 客户端 + client + + + 域名解析 + host + + + tcp隧道 + tcp + + + udp隧道 + udp + + + http代理 + http + + + socks5代理 + socks5 + + + 私密代理 + secret + + + p2p代理 + p2p + + + 文件代理 + file + + + 备注 + remark + + + 流量限制 + 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 header修改 + header modify + + + 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 + + + +