Merge remote-tracking branch 'origin/dev' into dev

pull/310/head
ffdfgdfg 2019-12-14 18:36:02 +08:00
commit def85f883b
34 changed files with 1277 additions and 1115 deletions

View File

@ -44,12 +44,12 @@ deploy:
- linux_mipsle_server.tar.gz
- linux_mips_client.tar.gz
- linux_mips_server.tar.gz
- macos_client.tar.gz
- macos_server.tar.gz
- win_386_client.tar.gz
- win_386_server.tar.gz
- win_amd64_client.tar.gz
- win_amd64_server.tar.gz
- darwin_amd64_client.tar.gz
- darwin_amd64_server.tar.gz
- windows_386_client.tar.gz
- windows_386_server.tar.gz
- windows_amd64_client.tar.gz
- windows_amd64_server.tar.gz
- npc_syno.spk
- npc_sdk.tar.gz
on:

1034
README.md

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
#/bash/sh
export VERSION=0.25.1
export VERSION=0.25.2
sudo apt-get install gcc-mingw-w64-i686
env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go
@ -69,17 +69,17 @@ tar -czvf linux_mips_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf win_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
tar -czvf windows_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf win_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
tar -czvf windows_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf macos_client.tar.gz npc conf/npc.conf conf/multi_account.conf
tar -czvf darwin_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
@ -146,17 +146,17 @@ tar -czvf linux_mipsle_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf macos_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
tar -czvf darwin_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf win_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
tar -czvf windows_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf win_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
tar -czvf windows_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

View File

@ -2,9 +2,12 @@ package main
import (
"flag"
"github.com/cnlh/nps/lib/install"
"log"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
@ -12,14 +15,13 @@ import (
"github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/daemon"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/install"
"github.com/cnlh/nps/lib/version"
"github.com/cnlh/nps/server"
"github.com/cnlh/nps/server/connection"
"github.com/cnlh/nps/server/test"
"github.com/cnlh/nps/server/tool"
"github.com/cnlh/nps/web/routers"
"github.com/kardianos/service"
)
var (
@ -29,20 +31,9 @@ var (
func main() {
flag.Parse()
beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "nps.conf"))
routers.Init()
if len(os.Args) > 1 {
switch os.Args[1] {
case "test":
test.TestServerConfig()
log.Println("test ok, no error")
return
case "start", "restart", "stop", "status", "reload":
daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath())
case "install":
install.InstallNps()
return
}
// init log
if err := beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "nps.conf")); err != nil {
log.Fatalln("load config file error", err.Error())
}
if level = beego.AppConfig.String("log_level"); level == "" {
level = "7"
@ -50,11 +41,99 @@ func main() {
logs.Reset()
logs.EnableFuncCallDepth(true)
logs.SetLogFuncCallDepth(3)
if *logType == "stdout" {
logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
} else {
logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+beego.AppConfig.String("log_path")+`","daily":false,"maxlines":100000,"color":true}`)
logPath := beego.AppConfig.String("log_path")
if logPath == "" {
logPath = common.GetLogPath()
}
if common.IsWindows() {
logPath = strings.Replace(logPath, "\\", "\\\\", -1)
}
logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+logPath+`","daily":false,"maxlines":100000,"color":true}`)
// init service
options := make(service.KeyValue)
options["Restart"] = "on-success"
options["SuccessExitStatus"] = "1 2 8 SIGKILL"
svcConfig := &service.Config{
Name: "Nps",
DisplayName: "nps内网穿透代理服务器",
Description: "一款轻量级、功能强大的内网穿透代理服务器。支持tcp、udp流量转发支持内网http代理、内网socks5代理同时支持snappy压缩、站点保护、加密传输、多路复用、header修改等。支持web图形化管理集成多用户模式。",
Option: options,
}
if !common.IsWindows() {
svcConfig.Dependencies = []string{
"Requires=network.target",
"After=network-online.target syslog.target"}
}
prg := &nps{}
prg.exit = make(chan struct{})
s, err := service.New(prg, svcConfig)
if err != nil {
logs.Error(err)
return
}
if len(os.Args) > 1 {
switch os.Args[1] {
case "debug":
logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
case "reload":
daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath())
return
case "install":
// uninstall before
service.Control(s, "uninstall")
binPath := install.InstallNps()
svcConfig.Executable = binPath
s, err := service.New(prg, svcConfig)
if err != nil {
logs.Error(err)
return
}
err = service.Control(s, os.Args[1])
if err != nil {
logs.Error("Valid actions: %q\n", service.ControlAction, err.Error())
}
return
case "start", "restart", "stop", "uninstall":
err := service.Control(s, os.Args[1])
if err != nil {
logs.Error("Valid actions: %q\n", service.ControlAction, err.Error())
}
return
case "update":
install.Update()
return
default:
logs.Error("command is not support")
return
}
}
s.Run()
}
type nps struct {
exit chan struct{}
}
func (p *nps) Start(s service.Service) error {
p.run()
return nil
}
func (p *nps) Stop(s service.Service) error {
close(p.exit)
return nil
}
func (p *nps) run() error {
defer func() {
if err := recover(); err != nil {
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
logs.Warning("nps: panic serving %v: %v\n%s", err, string(buf))
}
}()
routers.Init()
task := &file.Tunnel{
Mode: "webServer",
}
@ -68,5 +147,10 @@ func main() {
crypt.InitTls(filepath.Join(common.GetRunPath(), "conf", "server.pem"), filepath.Join(common.GetRunPath(), "conf", "server.key"))
tool.InitAllowPort()
tool.StartSystemInfo()
server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"))
go server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"))
select {
case <-p.exit:
logs.Warning("stop...")
}
return nil
}

View File

@ -26,7 +26,7 @@ public_vkey=123
# log level LevelEmergency->0 LevelAlert->1 LevelCritical->2 LevelError->3 LevelWarning->4 LevelNotice->5 LevelInformational->6 LevelDebug->7
log_level=7
log_path=nps.log
#log_path=nps.log
#Whether to restrict IP access, true or false or ignore
#ip_limit=true
@ -42,6 +42,9 @@ web_password=123
web_port = 8080
web_ip=0.0.0.0
web_base_url=
web_open_ssl=false
web_cert_file=conf/server.pem
web_key_file=conf/server.key
# if web under proxy use sub path. like http://host/nps need this.
#web_base_url=/nps

0
docs/.nojekyll Normal file
View File

21
docs/README.md Normal file
View File

@ -0,0 +1,21 @@
# 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管理端。
## 背景
![image](https://github.com/cnlh/nps/blob/master/image/web.png?raw=true)
1. 做微信公众号开发、小程序开发等----> 域名代理模式
2. 想在外网通过ssh连接内网的机器做云服务器到内网服务器端口的映射----> tcp代理模式
3. 在非内网环境下使用内网dns或者需要通过udp访问内网机器等----> udp代理模式
4. 在外网使用HTTP代理访问内网站点----> http代理模式
5. 搭建一个内网穿透ss在外网如同使用内网vpn一样访问内网资源或者设备----> socks5代理模式

14
docs/_coverpage.md Normal file
View File

@ -0,0 +1,14 @@
![logo](logo.svg)
# NPS <small>0.25.1</small>
> 一款轻量级、高性能、功能强大的内网穿透代理服务器
- 支持tcp、udp流量转发
- 支持内网http代理、内网socks5代理、p2p
- 简洁方便的WEB管理界面
- 服务端控制
[GitHub](https://github.com/cnlh/nps/)
[开始使用](#nps)

27
docs/_sidebar.md Normal file
View File

@ -0,0 +1,27 @@
* 入门
* [安装](install.md)
* [启动](run.md)
* [使用示例](example.md)
* 服务端
* [介绍](introduction.md)
* [使用](nps_use.md)
* [配置文件](server_config.md)
* [增强功能](nps_extend.md)
* 客户端
* [基本使用](use.md)
* [增强功能](npc_extend.md)
* 扩展
* [功能](feature.md)
* [说明](description.md)
* [web api](api.md)
* 其他
* [贡献](contribute.md)
* [捐助](donate.md)
* [致谢](thanks.md)
* [交流](discuss.md)

46
docs/api.md Normal file
View File

@ -0,0 +1,46 @@
# web api
## webAPI验证说明
- 采用auth_key的验证方式
- 在提交的每个请求后面附带两个参数,`auth_key` 和`timestamp`
```
auth_key的生成方式为md5(配置文件中的auth_key+当前时间戳)
```
```
timestamp为当前时间戳
```
```
curl --request POST \
--url http://127.0.0.1:8080/client/list \
--data 'auth_key=2a0000d9229e7dbcf79dd0f5e04bb084&timestamp=1553045344&start=0&limit=10'
```
**注意:** 为保证安全时间戳的有效范围为20秒内所以每次提交请求必须重新生成。
## 获取服务端时间
由于服务端与api请求的客户端时间差异不能太大所以提供了一个可以获取服务端时间的接口
```
POST /auth/gettime
```
## 获取服务端authKey
如果想获取authKey服务端提供获取authKey的接口
```
POST /auth/getauthkey
```
将返回加密后的authKey采用aes cbc加密请使用与服务端配置文件中cryptKey相同的密钥进行解密
**注意:** nps配置文件中`auth_crypt_key`需为16位
- 解密密钥长度128
- 偏移量与密钥相同
- 补码方式pkcs5padding
- 解密串编码方式 十六进制
## 详细文档
- **此文档近期可能更新较慢,建议自行抓包**
为方便第三方扩展在web模式下可利用webAPI进行相关操作详情见
[webAPI文档](https://github.com/cnlh/nps/wiki/webAPI%E6%96%87%E6%A1%A3)

6
docs/contribute.md Normal file
View File

@ -0,0 +1,6 @@
# 贡献
- 如果遇到bug可以直接提交至dev分支
- 使用遇到问题可以通过issues反馈
- 项目处于开发阶段,还有很多待完善的地方,如果可以贡献代码,请提交 PR 至 dev 分支
- 如果有新的功能特性反馈可以通过issues或者qq群反馈

26
docs/description.md Normal file
View File

@ -0,0 +1,26 @@
# 说明
## 获取用户真实ip
在域名代理模式中可以通过request请求 header 中的 X-Forwarded-For 和 X-Real-IP 来获取用户真实 IP。
**本代理前会在每一个http(s)请求中添加了这两个 header。**
## 热更新支持
对于绝大多数配置在web管理中的修改将实时使用无需重启客户端或者服务端
## 客户端地址显示
在web管理中将显示客户端的连接地址
## 流量统计
可统计显示每个代理使用的流量,由于压缩和加密等原因,会和实际环境中的略有差异
## 当前客户端带宽
可统计每个客户端当前的带宽,可能和实际有一定差异,仅供参考。
## 客户端与服务端版本对比
为了程序正常运行,客户端与服务端的核心版本必须一致,否则将导致客户端无法成功连接致服务端。
## Linux系统限制
默认情况下linux对连接数量有限制对于性能好的机器完全可以调整内核参数以处理更多的连接。
`tcp_max_syn_backlog` `somaxconn`
酌情调整参数,增强网络性能

3
docs/discuss.md Normal file
View File

@ -0,0 +1,3 @@
# 交流群
![二维码.jpeg](https://i.loli.net/2019/02/15/5c66c32a42074.jpeg)

7
docs/donate.md Normal file
View File

@ -0,0 +1,7 @@
# 捐助
如果您觉得nps对你有帮助欢迎给予我们一定捐助也是帮助nps更好的发展。
## 支付宝
![image](https://github.com/cnlh/nps/blob/master/image/donation_zfb.png?raw=true)
## 微信
![image](https://github.com/cnlh/nps/blob/master/image/donation_wx.png?raw=true)

121
docs/example.md Normal file
View File

@ -0,0 +1,121 @@
# 使用示例
## 统一准备工作(必做)
- 开启服务端假设公网服务器ip为1.1.1.1,配置文件中`bridge_port`为8284配置文件中`web_port`为8080
- 访问1.1.1.1:8080
- 在客户端管理中创建一个客户端,记录下验证密钥
- 内网客户端运行windows使用cmd运行加.exe
```shell
./npc -server=1.1.1.1:8284 -vkey=客户端的密钥
```
**注意:运行服务端后,请确保能从客户端设备上正常访问配置文件中所配置的`bridge_port`端口telnetnetcat这类的来检查**
## 域名解析
**适用范围:** 小程序开发、微信公众号开发、产品演示
**假设场景:**
- 有一个域名proxy.com有一台公网机器ip为1.1.1.1
- 两个内网开发站点127.0.0.1:81127.0.0.1:82
- 想通过http|https://a.proxy.com访问127.0.0.1:81通过http|https://b.proxy.com访问127.0.0.1:82
**使用步骤**
- 将*.proxy.com解析到公网服务器1.1.1.1
- 点击刚才创建的客户端的域名管理添加两条规则规则1、域名`a.proxy.com`,内网目标:`127.0.0.1:81`2、域名`b.proxy.com`,内网目标:`127.0.0.1:82`
现在访问http|https://`a.proxy.com``b.proxy.com`即可成功
**https:** 如需使用https请进行相关配置详见 [使用https](##使用https)
## tcp隧道
**适用范围:** ssh、远程桌面等tcp连接场景
**假设场景:**
想通过访问公网服务器1.1.1.1的8001端口连接内网机器10.1.50.101的22端口实现ssh连接
**使用步骤**
- 在刚才创建的客户端隧道管理中添加一条tcp隧道填写监听的端口8001、内网目标ip和目标端口10.1.50.101:22保存。
- 访问公网服务器ip1.1.1.1,填写的监听端口(8001)相当于访问内网ip(10.1.50.101):目标端口(22),例如:`ssh -p 8001 root@1.1.1.1`
## udp隧道
**适用范围:** 内网dns解析等udp连接场景
**假设场景:**
内网有一台dns10.1.50.102:53在非内网环境下想使用该dns公网服务器为1.1.1.1
**使用步骤**
- 在刚才创建的客户端的隧道管理中添加一条udp隧道填写监听的端口53、内网目标ip和目标端口10.1.50.102:53保存。
- 修改需要使用的dns地址为1.1.1.1则相当于使用10.1.50.102作为dns服务器
## socks5代理
**适用范围:** 在外网环境下如同使用vpn一样访问内网设备或者资源
**假设场景:**
想将公网服务器1.1.1.1的8003端口作为socks5代理达到访问内网任意设备或者资源的效果
**使用步骤**
- 在刚才创建的客户端隧道管理中添加一条socks5代理填写监听的端口8003保存。
- 在外网环境的本机配置socks5代理(例如使用proxifier进行全局代理)ip为公网服务器ip1.1.1.1),端口为填写的监听端口(8003),即可畅享内网了
**注意**
经过socks5代理当收到socks5数据包时socket已经是accept状态。表现是扫描端口全open建立连接后短时间关闭。若想同内网表现一致建议远程连接一台设备。
## http正向代理
**适用范围:** 在外网环境下使用http正向代理访问内网站点
**假设场景:**
想将公网服务器1.1.1.1的8004端口作为http代理访问内网网站
**使用步骤**
- 在刚才创建的客户端隧道管理中添加一条http代理填写监听的端口8004保存。
- 在外网环境的本机配置http代理ip为公网服务器ip1.1.1.1),端口为填写的监听端口(8004),即可访问了
## 私密代理
**适用范围:** 无需占用多余的端口、安全性要求较高可以防止其他人连接的tcp服务例如ssh。
**假设场景:**
无需新增多的端口实现访问内网服务器10.1.50.2的22端口
**使用步骤**
- 在刚才创建的客户端中添加一条私密代理并设置唯一密钥secrettest和内网目标10.1.50.2:22
- 在需要连接ssh的机器上以执行命令
```
./npc -server=1.1.1.1:8284 -vkey=vkey -type=tcp -password=secrettest -local_type=secret
```
如需指定本地端口可加参数`-local_port=xx`默认为2000
**注意:** password为web管理上添加的唯一密钥具体命令可查看web管理上的命令提示
假设10.1.50.2用户名为root现在执行`ssh -p 2000 root@1.1.1.1`即可访问ssh
## p2p服务
**适用范围:** 大流量传输场景流量不经过公网服务器但是由于p2p穿透和nat类型关系较大不保证100%成功支持大部分nat类型。[nat类型检测](##nat类型检测)
**假设场景:**
想通过访问使用端机器访问端也就是本机的2000端口---->访问到内网机器 10.2.50.2的22端口
**使用步骤**
- 在`nps.conf`中设置`p2p_ip`nps服务器ip和`p2p_port`nps服务器udp端口
- 在刚才刚才创建的客户端中添加一条p2p代理并设置唯一密钥p2pssh
- 在使用端机器(本机)执行命令
```
./npc -server=1.1.1.1:8284 -vkey=123 -password=p2pssh -target=10.2.50.2:22
```
如需指定本地端口可加参数`-local_port=xx`默认为2000
**注意:** password为web管理上添加的唯一密钥具体命令可查看web管理上的命令提示
假设内网机器为10.2.50.2的ssh用户名为root现在在本机上执行`ssh -p 2000 root@127.0.0.1`即可访问机器2的ssh如果是网站在浏览器访问127.0.0.1:2000端口即可。

247
docs/feature.md Normal file
View File

@ -0,0 +1,247 @@
# 扩展功能
## 缓存支持
对于web站点来说一些静态文件往往消耗更大的流量且在内网穿透中静态文件还需到客户端获取一次这将导致更大的流量消耗。nps在域名解析代理中支持对静态文件进行缓存。
即假设一个站点有a.cssnps将只需从npc客户端读取一次该文件然后把该文件的内容放在内存中下一次将不再对npc客户端进行请求而直接返回内存中的对应内容。该功能默认是关闭的如需开启请在`nps.conf`中设置`http_cache=true`,并设置`http_cache_length`缓存文件的个数消耗内存不宜过大0表示不限制个数
## 数据压缩支持
由于是内网穿透内网客户端与服务端之间的隧道存在大量的数据交换为节省流量加快传输速度由此本程序支持SNNAPY形式的压缩。
- 所有模式均支持数据压缩
- 在web管理或客户端配置文件中设置
## 加密传输
如果公司内网防火墙对外网访问进行了流量识别与屏蔽例如禁止了ssh协议等通过设置 配置文件,将服务端与客户端之间的通信内容加密传输,将会有效防止流量被拦截。
- nps使用tls加密所以一定要保留conf目录下的密钥文件同时也可以自行生成
- 在web管理或客户端配置文件中设置
## 站点保护
域名代理模式所有客户端共用一个http服务端口在知道域名后任何人都可访问一些开发或者测试环境需要保密所以可以设置用户名和密码nps将通过 Http Basic Auth 来保护,访问时需要输入正确的用户名和密码。
- 在web管理或客户端配置文件中设置
## host修改
由于内网站点需要的host可能与公网域名不一致域名代理支持host修改功能即修改request的header中的host字段。
**使用方法在web管理中设置**
## 自定义header
支持对header进行新增或者修改以配合服务的需要
## 404页面配置
支持域名解析模式的自定义404页面修改/web/static/page/error.html中内容即可暂不支持静态文件等内容
## 流量限制
支持客户端级流量限制,当该客户端入口流量与出口流量达到设定的总量后会拒绝服务
域名代理会返回404页面其他代理会拒绝连接,使用该功能需要在`nps.conf`中设置`allow_flow_limit`,默认是关闭的。
## 带宽限制
支持客户端级带宽限制,带宽计算方式为入口和出口总和,权重均衡,使用该功能需要在`nps.conf`中设置`allow_rate_limit`,默认是关闭的。
## 负载均衡
本代理支持域名解析模式和tcp代理的负载均衡在web域名添加或者编辑中内网目标分行填写多个目标即可实现轮训级别的负载均衡
## 端口白名单
为了防止服务端上的端口被滥用可在nps.conf中配置allow_ports限制可开启的端口忽略或者不填表示端口不受限制格式
```ini
allow_ports=9001-9009,10001,11000-12000
```
## 端口范围映射
当客户端以配置文件的方式启动时可以将本地的端口进行范围映射仅支持tcp和udp模式例如
```ini
[tcp]
mode=tcp
server_port=9001-9009,10001,11000-12000
target_port=8001-8009,10002,13000-14000
```
逗号分隔,可单个或者范围,注意上下端口的对应关系,无法一一对应将不能成功
## 端口范围映射到其他机器
```ini
[tcp]
mode=tcp
server_port=9001-9009,10001,11000-12000
target_port=8001-8009,10002,13000-14000
target_ip=10.1.50.2
```
填写target_ip后则表示映射的该地址机器的端口忽略则便是映射本地127.0.0.1,仅范围映射时有效
## 守护进程
本代理支持守护进程,使用示例如下,服务端客户端所有模式通用,支持linuxdarwinwindows。
```
./(nps|npc) start|stop|restart|status 若有其他参数可加其他参数
```
```
(nps|npc).exe start|stop|restart|status 若有其他参数可加其他参数
```
## KCP协议支持
KCP 是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%在弱网环境下对性能能有一定的提升。可在nps.conf中修改`bridge_type`为kcp
设置后本代理将开启udp端口`bridge_port`
注意当服务端为kcp时客户端连接时也需要使用相同配置无配置文件模式加上参数type=kcp,配置文件模式在配置文件中设置tp=kcp
## 域名泛解析
支持域名泛解析例如将host设置为*.proxy.coma.proxy.com、b.proxy.com等都将解析到同一目标在web管理中或客户端配置文件中将host设置为此格式即可。
## URL路由
本代理支持根据URL将同一域名转发到不同的内网服务器可在web中或客户端配置文件中设置此参数也可忽略例如在客户端配置文件中
```ini
[web1]
host=a.proxy.com
target_addr=127.0.0.1:7001
location=/test
[web2]
host=a.proxy.com
target_addr=127.0.0.1:7002
location=/static
```
对于`a.proxy.com/test`将转发到`web1`,对于`a.proxy.com/static`将转发到`web2`
## 限制ip访问
如果将一些危险性高的端口例如ssh端口暴露在公网上可能会带来一些风险本代理支持限制ip访问。
**使用方法:** 在配置文件nps.conf中设置`ip_limit`=true设置后仅通过注册的ip方可访问。
**ip注册**
**方式一:**
在需要访问的机器上,运行客户端
```
./npc register -server=ip:port -vkey=公钥或客户端密钥 time=2
```
time为有效小时数例如time=2在当前时间后的两小时内本机公网ip都可以访问nps代理.
**方式二:**
此外nps的web登陆也可提供验证的功能成功登陆nps web admin后将自动为登陆的ip注册两小时的允许访问权限。
**注意:** 本机公网ip并不是一成不变的请自行注意有效期的设置同时同一网络下多人也可能是在公用同一个公网ip。
## 客户端最大连接数
为防止恶意大量长连接影响服务端程序的稳定性可以在web或客户端配置文件中为每个客户端设置最大连接数。该功能针对`socks5`、`http正向代理`、`域名代理`、`tcp代理`、`udp代理`、`私密代理`生效,使用该功能需要在`nps.conf`中设置`allow_connection_num_limit=true`,默认是关闭的。
## 客户端最大隧道数限制
nps支持对客户端的隧道数量进行限制该功能默认是关闭的如需开启请在`nps.conf`中设置`allow_tunnel_num_limit=true`。
## 端口复用
在一些严格的网络环境中对端口的个数等限制较大nps支持强大端口复用功能。将`bridge_port`、 `http_proxy_port``https_proxy_port` 、`web_port`都设置为同一端口,也能正常使用。
- 使用时将需要复用的端口设置为与`bridge_port`一致即可,将自动识别。
- 如需将web管理的端口也复用需要配置`web_host`也就是一个二级域名以便区分
## 多路复用
nps主要通信默认基于多路复用无需开启。
多路复用基于TCP滑动窗口原理设计动态计算延迟以及带宽来算出应该往网络管道中打入的流量。
由于主要通信大多采用TCP协议并无法探测其实时丢包情况对于产生丢包重传的情况采用较大的宽容度
5分钟的等待时间超时将会关闭当前隧道连接并重新建立这将会抛弃当前所有的连接。
在Linux上可以通过调节内核参数来适应不同应用场景。
对于需求大带宽又有一定的丢包的场景,可以保持默认参数不变,尽可能少抛弃连接
高并发下可根据[Linux系统限制](## Linux系统限制) 调整
对于延迟敏感而又有一定丢包的场景可以适当调整TCP重传次数
`tcp_syn_retries`, `tcp_retries1`, `tcp_retries2`
高并发同上
nps会在系统主动关闭连接的时候拿到报错进而重新建立隧道连接
## 环境变量渲染
npc支持环境变量渲染以适应在某些特殊场景下的要求。
**在无配置文件启动模式下:**
设置环境变量
```
export NPC_SERVER_ADDR=1.1.1.1:8284
export NPC_SERVER_VKEY=xxxxx
```
直接执行./npc即可运行
**在配置文件启动模式下:**
```ini
[common]
server_addr={{.NPC_SERVER_ADDR}}
conn_type=tcp
vkey={{.NPC_SERVER_VKEY}}
auto_reconnection=true
[web]
host={{.NPC_WEB_HOST}}
target_addr={{.NPC_WEB_TARGET}}
```
在配置文件中填入相应的环境变量名称npc将自动进行渲染配置文件替换环境变量
## 健康检查
当客户端以配置文件模式启动时,支持多节点的健康检查。配置示例如下
```ini
[health_check_test1]
health_check_timeout=1
health_check_max_failed=3
health_check_interval=1
health_http_url=/
health_check_type=http
health_check_target=127.0.0.1:8083,127.0.0.1:8082
[health_check_test2]
health_check_timeout=1
health_check_max_failed=3
health_check_interval=1
health_check_type=tcp
health_check_target=127.0.0.1:8083,127.0.0.1:8082
```
**health关键词必须在开头存在**
第一种是http模式也就是以get的方式请求目标+url返回状态码为200表示成功
第一种是tcp模式也就是以tcp的方式与目标建立连接能成功建立连接表示成功
如果失败次数超过`health_check_max_failed`nps则会移除该npc下的所有该目标如果失败后目标重新上线nps将自动将目标重新加入。
项 | 含义
---|---
health_check_timeout | 健康检查超时时间
health_check_max_failed | 健康检查允许失败次数
health_check_interval | 健康检查间隔
health_check_type | 健康检查类型
health_check_target | 健康检查目标,多个以逗号(,)分隔
health_check_type | 健康检查类型
health_http_url | 健康检查url仅http模式适用
## 日志输出
日志输出级别
**对于npc**
```
-log_level=0~7 -log_path=npc.log
```
```
LevelEmergency->0 LevelAlert->1
LevelCritical->2 LevelError->3
LevelWarning->4 LevelNotice->5
LevelInformational->6 LevelDebug->7
```
默认为全输出,级别为0到7
**对于nps**
在`nps.conf`中设置相关配置即可

42
docs/index.html Normal file
View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="description" content="Description">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
</head>
<body>
<div id="app"></div>
<script src="//unpkg.com/docsify-edit-on-github/index.js"></script>
<script>
window.$docsify = {
name: '',
repo: '',
loadSidebar: true,
coverpage: true,
subMaxLevel: 2,
maxLevel: 4,
search: {
noData: "没有结果",
paths: 'auto',
placeholder: "搜索",
hideOtherSidebarContent: true, // whether or not to hide other sidebar content
},
plugins: [
EditOnGithubPlugin.create("https://github.com/cnlh/nps/tree/master/docs/", "", "在github上编辑"),
]
}
</script>
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
<script src="//unpkg.com/docsify-copy-code"></script>
</body>
</html>

19
docs/install.md Normal file
View File

@ -0,0 +1,19 @@
# 安装
## 安装包安装
[releases](https://github.com/cnlh/nps/releases)
下载对应的系统版本即可,服务端和客户端是单独的
## 源码安装
- 安装源码
```go get -u github.com/cnlh/nps...
```
- 编译
服务端```go build cmd/nps/nps.go```
客户端```go build cmd/npc/npc.go```
## docker安装
> [server](https://hub.docker.com/r/ffdfgdfg/nps)
> [client](https://hub.docker.com/r/ffdfgdfg/npc)

4
docs/introduction.md Normal file
View File

@ -0,0 +1,4 @@
![image](https://github.com/cnlh/nps/blob/master/image/web2.png?raw=true)
# 介绍
可在网页上配置和管理各个tcp、udp隧道、内网站点代理http、https解析等功能强大操作方便。

BIN
docs/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

1
docs/logo.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576165662444" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="50156" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><defs><style type="text/css"></style></defs><path d="M414.764 498.138c-4.094-8.188-13-12.844-22.094-11.562L181.58 516.73a21.496 21.496 0 0 0-12.062 6.032L48.926 643.4c-8.344 8.344-8.344 21.842 0 30.154l90.436 90.466c8.344 8.312 21.844 8.312 30.156 0l241.246-241.26a21.344 21.344 0 0 0 4-24.622zM507.262 842.428l30.156-211.09c1.312-9.094-3.376-17.968-11.562-22.094a21.34 21.34 0 0 0-24.624 4L259.984 854.49c-8.312 8.312-8.312 21.812 0 30.156l90.468 90.464c8.344 8.312 21.842 8.312 30.156 0l120.624-120.622a21.214 21.214 0 0 0 6.03-12.06z" fill="#DA4453" p-id="50157"></path><path d="M732.444 186.238a21.254 21.254 0 0 0-14.75-15.156l-93.778-26.876a21.288 21.288 0 0 0-20.938 5.438l-87.188 87.154a21.266 21.266 0 0 0-5.656 19.968 21.088 21.088 0 0 0 5.656 10.188 21.33 21.33 0 0 0 8.344 5.156l90.468 30.156a21.27 21.27 0 0 0 21.812-5.156l90.464-90.468a21.252 21.252 0 0 0 5.566-20.404zM879.786 400.078l-26.842-93.75a21.348 21.348 0 0 0-15.156-14.78 21.388 21.388 0 0 0-20.438 5.562l-90.468 90.466a21.348 21.348 0 0 0-5.156 21.812l30.156 90.466a21.33 21.33 0 0 0 5.156 8.344 21.4 21.4 0 0 0 10.188 5.688 21.356 21.356 0 0 0 19.968-5.688l87.186-87.156a21.39 21.39 0 0 0 5.406-20.964z" fill="#434A54" p-id="50158"></path><path d="M997.284 138.206c30.312-61.56 34.876-103.592 13.5-124.966-21.376-21.374-63.438-16.842-124.998 13.5-47.06 23.188-97.592 58.28-128.748 89.436L6.27 866.99c-4 4-6.25 9.406-6.25 15.062s2.25 11.094 6.25 15.094l120.624 120.59c8.312 8.344 21.812 8.344 30.156 0l750.768-750.782c31.154-31.156 66.278-81.686 89.466-128.748z" fill="#E6E9ED" p-id="50159"></path><path d="M907.816 266.954c31.154-31.156 66.28-81.686 89.466-128.748 30.312-61.56 34.876-103.592 13.5-124.966-21.376-21.374-63.438-16.842-124.998 13.5-47.06 23.188-97.592 58.28-128.748 89.436l150.78 150.778z" fill="#ED5564" p-id="50160"></path><path d="M157.048 1017.736l15.062-15.062-150.778-150.778-15.062 15.094c-4 4-6.25 9.406-6.25 15.062s2.25 11.094 6.25 15.094l120.624 120.59c8.312 8.344 21.81 8.344 30.154 0z" fill="#FFCE54" p-id="50161"></path><path d="M81.662 972.546l-30.156-30.156 30.156-30.154L111.814 942.39z" fill="#F6BB42" p-id="50162"></path><path d="M199.672 824.334c-8.312-8.344-8.312-21.844 0-30.156l241.246-241.246c8.344-8.312 21.844-8.312 30.156 0 8.344 8.344 8.344 21.844 0 30.156L229.828 824.334c-8.312 8.312-21.812 8.312-30.156 0z" fill="#ED5564" p-id="50163"></path><path d="M787.194 236.798c-8.312-8.312-21.812-8.312-30.156 0l-120.622 120.624c-8.312 8.344-8.312 21.844 0 30.156 8.342 8.344 21.842 8.344 30.154 0l120.624-120.624c8.344-8.312 8.344-21.812 0-30.156z" fill="#656D78" p-id="50164"></path><path d="M997.284 138.206c30.312-61.56 34.876-103.592 13.5-124.966a40.728 40.728 0 0 0-8.562-6.562c13.376 23.156 6.688 62.25-20.032 116.466-23.188 47.062-58.312 97.592-89.436 128.748L141.954 1002.674c-8.312 8.312-21.812 8.312-30.156 0l-60.312-60.31-45.216-45.248v0.032l120.624 120.59c8.312 8.344 21.812 8.344 30.156 0l750.768-750.782c31.154-31.158 66.278-81.688 89.466-128.75z" fill="#FFFFFF" opacity=".2" p-id="50165"></path></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

36
docs/npc_extend.md Normal file
View File

@ -0,0 +1,36 @@
# 增强功能
## nat类型检测
```
./npc nat
```
如果p2p双方都是Symmetric Nat肯定不能成功其他组合都有较大成功率。
## 状态检查
```
./npc status -config=npc配置文件路径
```
## 重载配置文件
```
./npc restart -config=npc配置文件路径
```
## 通过代理连接nps
有时候运行npc的内网机器无法直接访问外网此时可以可以通过socks5代理连接nps
对于配置文件方式启动,设置
```ini
[common]
proxy_url=socks5://111:222@127.0.0.1:8024
```
对于无配置文件模式,加上参数
```
-proxy=socks5://111:222@127.0.0.1:8024
```
支持socks5和http两种模式
即socks5://username:password@ip:port
或http://username:password@ip:port
## 群晖支持
可在releases中下载spk群晖套件例如`npc_x64-6.1_0.19.0-1.spk`

107
docs/nps_extend.md Normal file
View File

@ -0,0 +1,107 @@
# 增强功能
## 使用https
**方式一:** 类似于nginx实现https的处理
在配置文件中将https_proxy_port设置为443或者其他你想配置的端口和在web中对应域名编辑中设置对应的证书路径将`https_just_proxy`设置为false然后就和http代理一样了
**此外:** 可以在`nps.conf`中设置一个默认的https配置当遇到未在web中设置https证书的域名解析时将自动使用默认证书另还有一种情况就是对于某些请求的clienthello不携带sni扩展信息nps也将自动使用默认证书
**方式二:** 在内网对应服务器上设置https
在`nps.conf`中将`https_just_proxy`设置为true并且打开`https_proxy_port`端口然后nps将直接转发https请求到内网服务器上由内网服务器进行https处理
## 与nginx配合
有时候我们还需要在云服务器上运行nginx来保证静态文件缓存等本代理可和nginx配合使用在配置文件中将httpProxyPort设置为非80端口并在nginx中配置代理例如httpProxyPort为8024时
```
server {
listen 80;
server_name *.proxy.com;
location / {
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8024;
}
}
```
如需使用https也可在nginx监听443端口并配置ssl并将本代理的httpsProxyPort设置为空关闭https即可例如httpProxyPort为8024时
```
server {
listen 443;
server_name *.proxy.com;
ssl on;
ssl_certificate certificate.crt;
ssl_certificate_key private.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8024;
}
}
```
## web管理使用https
如果web管理需要使用https可以在配置文件`nps.conf`中设置`web_open_ssl=true`,并配置`web_cert_file`和`web_key_file`
## 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设置为空。
## 流量数据持久化
服务端支持将流量数据持久化,默认情况下是关闭的,如果有需求可以设置`nps.conf`中的`flow_store_interval`参数,单位为分钟
**注意:** nps不会持久化通过公钥连接的客户端
## 系统信息显示
nps服务端支持在web上显示和统计服务器的相关信息但默认一些统计图表是关闭的如需开启请在`nps.conf`中设置`system_info_display=true`
## 自定义客户端连接密钥
web上可以自定义客户端连接的密钥但是必须具有唯一性
## 关闭公钥访问
可以将`nps.conf`中的`public_vkey`设置为空或者删除
## 关闭web管理
可以将`nps.conf`中的`web_port`设置为空或者删除
## 服务端多用户登陆
如果将`nps.conf`中的`allow_user_login`设置为true,服务端web将支持多用户登陆登陆用户名为user默认密码为每个客户端的验证密钥登陆后可以进入客户端编辑修改web登陆的用户名和密码默认该功能是关闭的。
## 用户注册功能
nps服务端支持用户注册功能可将`nps.conf`中的`allow_user_register`设置为true开启后登陆页将会有有注册功能
## 监听指定ip
nps支持每个隧道监听不同的服务端端口,在`nps.conf`中设置`allow_multi_ip=true`后可在web中控制或者npc配置文件中(可忽略默认为0.0.0.0)
```ini
server_ip=xxx
```
## 代理到服务端本地
在使用nps监听80或者443端口时默认是将所有的请求都会转发到内网上但有时候我们的nps服务器的上一些服务也需要使用这两个端口nps提供类似于`nginx` `proxy_pass` 的功能支持将代理到服务器本地该功能支持域名解析tcp、udp隧道默认关闭。
**即:** 假设在nps的vps服务器上有一个服务使用5000端口这时候nps占用了80端口和443我们想能使用一个域名通过http(s)访问到5000的服务。
**使用方式:** 在`nps.conf`中设置`allow_local_proxy=true`然后在web上设置想转发的隧道或者域名然后选择转发到本地选项即可成功。

21
docs/nps_use.md Normal file
View File

@ -0,0 +1,21 @@
# 使用
**提示使用web模式时服务端执行文件必须在项目根目录否则无法正确加载配置文件**
## web管理
进入web界面公网ip:web界面端口默认8080密码默认为123
进入web管理界面有详细的说明
## 服务端配置文件重载
```shell
sudo nps reload
```
**说明:** 仅支持部分配置重载,例如`allow_user_login` `auth_crypt_key` `auth_key` `web_username` `web_password` 等,未来将支持更多
## 服务端停止或重启
如果是daemon启动
```shell
./nps stop|restart
```

31
docs/run.md Normal file
View File

@ -0,0 +1,31 @@
# 启动
## 服务端
下载完服务器压缩包后,解压,然后进入解压后的文件夹
- 执行安装命令
对于linux|darwin ```sudo ./nps install```
对于windows管理员身份运行cmd进入安装目录 ```nps.exe install```
- 启动
对于linux|darwin ```sudo nps start```
对于windows管理员身份运行cmd进入程序目录 ```nps.exe start```
停止和重启可用start和restart
**如果发现没有启动成功,可以查看日志(Windows日志文件位于当前运行目录下linux和darwin位于/var/log/nps.log)**
- 访问服务端ip:web服务端口默认为8080
- 使用用户名和密码登陆默认admin/123正式使用一定要更改
- 创建客户端
## 客户端
- 下载客户端安装包并解压,进入到解压目录
- 点击web管理中客户端前的+号,复制启动命令
- 执行启动命令linux直接执行即可windows将./npc换成npc.exe用cmd执行
## 配置
- 客户端连接后在web中配置对应穿透服务即可
- 可以查看[使用示例](/example)

21
docs/server_config.md Normal file
View File

@ -0,0 +1,21 @@
# 服务端配置文件
- /conf/nps.conf
名称 | 含义
---|---
web_port | web管理端口
web_password | web界面管理密码
web_username | web界面管理账号
web_base_url | web管理主路径,用于将web管理置于代理子路径后面
bridge_port | 服务端客户端通信端口
https_proxy_port | 域名代理https代理监听端口
http_proxy_port | 域名代理http代理监听端口
auth_key|web api密钥
bridge_type|客户端与服务端连接方式kcp或tcp
public_vkey|客户端以配置文件模式启动时的密钥,设置为空表示关闭客户端配置文件连接模式
ip_limit|是否限制ip访问true或false或忽略
flow_store_interval|服务端流量数据持久化间隔,单位分钟,忽略表示不持久化
log_level|日志输出级别
auth_crypt_key | 获取服务端authKey时的aes加密密钥16位
p2p_ip| 服务端Ip使用p2p模式必填
p2p_port|p2p模式开启的udp端口

5
docs/thanks.md Normal file
View File

@ -0,0 +1,5 @@
Thanks [jetbrains](https://www.jetbrains.com/?from=nps) for providing development tools for nps
<html>
<img src="https://ftp.bmp.ovh/imgs/2019/12/6435398b0c7402b1.png" width="300" align=center />
</html>

208
docs/use.md Normal file
View File

@ -0,0 +1,208 @@
# 基本使用
## 无配置文件模式
此模式的各种配置在服务端web管理中完成,客户端除运行一条命令外无需任何其他设置
```
./npc -server=ip:port -vkey=web界面中显示的密钥
```
## 配置文件模式
此模式使用nps的公钥或者客户端私钥验证各种配置在客户端完成同时服务端web也可以进行管理
```
./npc -config=npc配置文件路径
```
可自行添加systemd service例如`npc.service`
```
[Unit]
Description=npc - convenient proxy server client
Documentation=https://github.com/cnlh/nps/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=simple
KillMode=process
Restart=always
RestartSec=15s
StandardOutput=append:/var/log/nps/npc.log
ExecStartPre=/bin/echo 'Starting npc'
ExecStopPost=/bin/echo 'Stopping npc'
ExecStart=/absolutely path to/npc -server=ip:port -vkey=web界面中显示的密钥
[Install]
WantedBy=multi-user.target
```
## 配置文件说明
[示例配置文件](https://github.com/cnlh/nps/tree/master/conf/npc.conf)
#### 全局配置
```ini
[common]
server_addr=1.1.1.1:8284
conn_type=tcp
vkey=123
username=111
password=222
compress=true
crypt=true
rate_limit=10000
flow_limit=100
remark=test
max_conn=10
```
项 | 含义
---|---
server_addr | 服务端ip:port
conn_type | 与服务端通信模式(tcp或kcp)
vkey|服务端配置文件中的密钥(非web)
username|socks5或http(s)密码保护用户名(可忽略)
password|socks5或http(s)密码保护密码(可忽略)
compress|是否压缩传输(true或false或忽略)
crypt|是否加密传输(true或false或忽略)
rate_limit|速度限制,可忽略
flow_limit|流量限制,可忽略
remark|客户端备注,可忽略
max_conn|最大连接数,可忽略
#### 域名代理
```ini
[common]
server_addr=1.1.1.1:8284
vkey=123
[web1]
host=a.proxy.com
target_addr=127.0.0.1:8080,127.0.0.1:8082
host_change=www.proxy.com
header_set_proxy=nps
```
项 | 含义
---|---
web1 | 备注
host | 域名(http|https都可解析)
target_addr|内网目标,负载均衡时多个目标,逗号隔开
host_change|请求host修改
header_xxx|请求header修改或添加header_proxy表示添加header proxy:nps
#### tcp隧道模式
```ini
[common]
server_addr=1.1.1.1:8284
vkey=123
[tcp]
mode=tcp
target_addr=127.0.0.1:8080
server_port=9001
```
项 | 含义
---|---
mode | tcp
server_port | 在服务端的代理端口
tartget_addr|内网目标
#### udp隧道模式
```ini
[common]
server_addr=1.1.1.1:8284
vkey=123
[udp]
mode=udp
target_addr=127.0.0.1:8080
server_port=9002
```
项 | 含义
---|---
mode | udp
server_port | 在服务端的代理端口
target_addr|内网目标
#### http代理模式
```ini
[common]
server_addr=1.1.1.1:8284
vkey=123
[http]
mode=httpProxy
server_port=9003
```
项 | 含义
---|---
mode | httpProxy
server_port | 在服务端的代理端口
#### socks5代理模式
```ini
[common]
server_addr=1.1.1.1:8284
vkey=123
[socks5]
mode=socks5
server_port=9004
multi_account=multi_account.conf
```
项 | 含义
---|---
mode | socks5
server_port | 在服务端的代理端口
multi_account | socks5多账号配置文件可选),配置后使用basic_username和basic_password无法通过认证
#### 私密代理模式
```ini
[common]
server_addr=1.1.1.1:8284
vkey=123
[secret_ssh]
mode=secret
password=ssh2
target_addr=10.1.50.2:22
```
项 | 含义
---|---
mode | secret
password | 唯一密钥
target_addr|内网目标
#### p2p代理模式
```ini
[common]
server_addr=1.1.1.1:8284
vkey=123
[p2p_ssh]
mode=p2p
password=ssh2
target_addr=10.1.50.2:22
```
项 | 含义
---|---
mode | p2p
password | 唯一密钥
target_addr|内网目标
#### 文件访问模式
利用nps提供一个公网可访问的本地文件服务此模式仅客户端使用配置文件模式方可启动
```ini
[common]
server_addr=1.1.1.1:8284
vkey=123
[file]
mode=file
server_port=9100
local_path=/tmp/
strip_pre=/web/
````
项 | 含义
---|---
mode | file
server_port | 服务端开启的端口
local_path|本地文件目录
strip_pre|前缀
对于`strip_pre`,访问公网`ip:9100/web/`相当于访问`/tmp/`目录
#### 断线重连
```ini
[common]
auto_reconnection=true
```

4
go.mod
View File

@ -6,10 +6,14 @@ require (
fyne.io/fyne v1.2.0
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
github.com/astaxie/beego v1.12.0
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d
github.com/dsnet/compress v0.0.1 // indirect
github.com/go-ole/go-ole v1.2.4 // indirect
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
github.com/kardianos/service v1.0.0 // indirect
github.com/klauspost/cpuid v1.2.1 // indirect
github.com/klauspost/pgzip v1.2.1 // indirect
github.com/klauspost/reedsolomon v1.9.2 // indirect
github.com/panjf2000/ants/v2 v2.2.2
github.com/pkg/errors v0.8.1

17
go.sum
View File

@ -9,6 +9,8 @@ github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkK
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c h1:aprLqMn7gSPT+vdDSl+/E6NLEuArwD/J7IWd8bJt5lQ=
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c/go.mod h1:Ie6SubJv/NTO9Q0UBH0QCl3Ve50lu9hjbi5YJUw03TE=
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io=
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE=
@ -19,6 +21,9 @@ github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFl
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
@ -26,6 +31,8 @@ github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8
github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gen2brain/go-unarr v0.0.0-20190203132630-dd30f8db8e40 h1:rnd7FAy39Y3+YOboqzQmGj62n9lJMoMr1TlIc1FTd/o=
github.com/gen2brain/go-unarr v0.0.0-20190203132630-dd30f8db8e40/go.mod h1:29wlntTq0xoOBDzoKlxLhCDh/G2GqMBam0P17/tMslE=
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw=
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f h1:7MsFMbSn8Lcw0blK4+NEOf8DuHoOBDhJsHz04yh13pM=
@ -42,8 +49,15 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
github.com/josephspurrier/goversioninfo v0.0.0-20190124120936-8611f5a5ff3f/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
github.com/kardianos/service v1.0.0 h1:HgQS3mFfOlyntWX8Oke98JcJLqt1DBcHR4kxShpYef0=
github.com/kardianos/service v1.0.0/go.mod h1:8CzDhVuCuugtsHyZoTvsOBuvonN/UDBvl0kH+BUxvbo=
github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/klauspost/reedsolomon v1.9.2 h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18=
github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@ -83,6 +97,8 @@ github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b h1:mnG1fcsIB1d/3vbkB
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
github.com/tjfoc/gmsm v1.0.1 h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU=
github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/xtaci/kcp-go v5.4.4+incompatible h1:QIJ0a0Q0N1G20yLHL2+fpdzyy2v/Cb3PI+xiwx/KK9c=
github.com/xtaci/kcp-go v5.4.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
@ -101,6 +117,7 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4r
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M=

View File

@ -48,9 +48,9 @@ func IsWindows() bool {
func GetLogPath() string {
var path string
if IsWindows() {
path = GetAppPath()
path = filepath.Join(GetAppPath(), "nps.log")
} else {
path = "/tmp"
path = "/var/log/nps.log"
}
return path
}

View File

@ -1,99 +1,123 @@
package install
import (
"encoding/json"
"errors"
"fmt"
"github.com/c4milo/unpackit"
"github.com/cnlh/nps/lib/common"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/cnlh/nps/lib/common"
)
func InstallNps() {
unit := `[Unit]
Description=nps - convenient proxy server
Documentation=https://github.com/cnlh/nps/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target`
service := `[Service]
Type=simple
KillMode=process
Restart=always
RestartSec=15s
StandardOutput=append:/var/log/nps/nps.log
ExecStartPre=/bin/echo 'Starting nps'
ExecStopPost=/bin/echo 'Stopping nps'
ExecStart=`
install := `[Install]
WantedBy=multi-user.target`
func Update() {
downloadLatest()
}
path := common.GetInstallPath()
if common.FileExists(path) {
log.Fatalf("the path %s has exist, does not support install", path)
type release struct {
TagName string `json:"tag_name"`
}
func downloadLatest() {
// get version
data, err := http.Get("https://api.github.com/repos/cnlh/nps/releases/latest")
if err != nil {
log.Fatal(err.Error())
}
MkidrDirAll(path, "conf", "web/static", "web/views")
b, err := ioutil.ReadAll(data.Body)
if err != nil {
log.Fatal(err)
}
rl := new(release)
json.Unmarshal(b, &rl)
version := rl.TagName
fmt.Println("the latest version is", version)
filename := runtime.GOOS + "_" + runtime.GOARCH + "_server" + ".tar.gz"
// download latest package
downloadUrl := fmt.Sprintf("https://github.com/cnlh/nps/releases/download/%s/%s", version, filename)
fmt.Println("download package from ", downloadUrl)
resp, err := http.Get(downloadUrl)
if err != nil {
log.Fatal(err.Error())
}
destPath, err := unpackit.Unpack(resp.Body, "")
if err != nil {
log.Fatal(err)
}
destPath = strings.Replace(destPath, "/web", "", -1)
destPath = strings.Replace(destPath, `\web`, "", -1)
destPath = strings.Replace(destPath, "/views", "", -1)
destPath = strings.Replace(destPath, `\views`, "", -1)
//复制文件到对应目录
if err := CopyDir(filepath.Join(common.GetAppPath(), "web", "views"), filepath.Join(path, "web", "views")); err != nil {
log.Fatalln(err)
}
if err := CopyDir(filepath.Join(common.GetAppPath(), "web", "static"), filepath.Join(path, "web", "static")); err != nil {
log.Fatalln(err)
}
if err := CopyDir(filepath.Join(common.GetAppPath(), "conf"), filepath.Join(path, "conf")); err != nil {
log.Fatalln(err)
copyStaticFile(destPath)
fmt.Println("Update completed, please restart")
if common.IsWindows() {
fmt.Println("windows 请将nps_new.exe替换成nps.exe")
}
}
func copyStaticFile(srcPath string) string {
path := common.GetInstallPath()
//复制文件到对应目录
if err := CopyDir(filepath.Join(srcPath, "web", "views"), filepath.Join(path, "web", "views")); err != nil {
log.Fatalln(err)
}
os.Chmod(filepath.Join(path, "web", "views"), 0766)
if err := CopyDir(filepath.Join(srcPath, "web", "static"), filepath.Join(path, "web", "static")); err != nil {
log.Fatalln(err)
}
os.Chmod(filepath.Join(path, "web", "static"), 0766)
binPath, _ := filepath.Abs(os.Args[0])
if !common.IsWindows() {
if _, err := copyFile(filepath.Join(common.GetAppPath(), "nps"), "/usr/bin/nps"); err != nil {
if _, err := copyFile(filepath.Join(common.GetAppPath(), "nps"), "/usr/local/bin/nps"); err != nil {
if _, err := copyFile(filepath.Join(srcPath, "nps"), "/usr/bin/nps"); err != nil {
if _, err := copyFile(filepath.Join(srcPath, "nps"), "/usr/local/bin/nps"); err != nil {
log.Fatalln(err)
} else {
os.Chmod("/usr/local/bin/nps", 0755)
service += "/usr/local/bin/nps"
log.Println("Executable files have been copied to", "/usr/local/bin/nps")
binPath = "/usr/local/bin/nps"
}
} else {
os.Chmod("/usr/bin/nps", 0755)
service += "/usr/bin/nps"
log.Println("Executable files have been copied to", "/usr/bin/nps")
binPath = "/usr/bin/nps"
}
systemd := unit + "\n\n" + service + "\n\n" + install
if _, err := os.Stat("/usr/lib/systemd/system"); os.IsExist(err) {
_ = os.Remove("/usr/lib/systemd/system/nps.service")
err := ioutil.WriteFile("/usr/lib/systemd/system/nps.service", []byte(systemd), 0644)
if err != nil {
log.Println("Write systemd service err ", err)
}
} else if _, err := os.Stat("/lib/systemd/system"); os.IsExist(err) {
_ = os.Remove("/lib/systemd/system/nps.service")
err := ioutil.WriteFile("/lib/systemd/system/nps.service", []byte(systemd), 0644)
if err != nil {
log.Println("Write systemd service err ", err)
}
} else {
log.Println("Write systemd service fail, not found the systemd system path ")
}
_ = os.Mkdir("/var/log/nps", 644)
} else {
copyFile(filepath.Join(srcPath, "nps.exe"), filepath.Join(common.GetAppPath(), "nps_new.exe"))
}
os.Chmod(binPath, 0755)
return binPath
}
func InstallNps() string {
path := common.GetInstallPath()
if common.FileExists(path) {
MkidrDirAll(path, "web/static", "web/views")
} else {
MkidrDirAll(path, "conf", "web/static", "web/views")
// not copy config if the config file is exist
if err := CopyDir(filepath.Join(common.GetAppPath(), "conf"), filepath.Join(path, "conf")); err != nil {
log.Fatalln(err)
}
os.Chmod(filepath.Join(path, "conf"), 0766)
}
binPath := copyStaticFile(common.GetAppPath())
log.Println("install ok!")
log.Println("Static files and configuration files in the current directory will be useless")
log.Println("The new configuration file is located in", path, "you can edit them")
if !common.IsWindows() {
log.Println(`You can start with:
sudo systemctl enable|disable|start|stop|restart|status nps
or:
nps test|start|stop|restart|status
nps start|stop|restart|uninstall|update
anywhere!`)
} else {
log.Println(`You can copy executable files to any directory and start working with:
nps.exe test|start|stop|restart|status
nps.exe start|stop|restart|uninstall|update
now!`)
}
os.Chmod(common.GetLogPath(), 0777)
return binPath
}
func MkidrDirAll(path string, v ...string) {
for _, item := range v {
@ -130,6 +154,7 @@ func CopyDir(srcPath string, destPath string) error {
destNewPath := strings.Replace(path, srcPath, destPath, -1)
log.Println("copy file ::" + path + " to " + destNewPath)
copyFile(path, destNewPath)
os.Chmod(destNewPath, 0766)
}
return nil
})

View File

@ -1,6 +1,6 @@
package version
const VERSION = "0.25.1"
const VERSION = "0.25.2"
// Compulsory minimum version, Minimum downward compatibility to this version
func GetVersion() string {

View File

@ -65,13 +65,21 @@ func (s *WebServer) Start() error {
beego.BConfig.WebConfig.Session.SessionOn = true
beego.SetStaticPath(beego.AppConfig.String("web_base_url")+"/static", filepath.Join(common.GetRunPath(), "web", "static"))
beego.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views"))
if l, err := connection.GetWebManagerListener(); err == nil {
err := errors.New("Web management startup failure ")
var l net.Listener
if l, err = connection.GetWebManagerListener(); err == nil {
beego.InitBeforeHTTPRun()
http.Serve(l, beego.BeeApp.Handlers)
if beego.AppConfig.String("web_open_ssl") == "true" {
keyPath := beego.AppConfig.String("web_key_file")
certPath := beego.AppConfig.String("web_cert_file")
err = http.ServeTLS(l, beego.BeeApp.Handlers, certPath, keyPath)
} else {
err = http.Serve(l, beego.BeeApp.Handlers)
}
} else {
logs.Error(err)
}
return errors.New("Web management startup failure")
return err
}
func (s *WebServer) Close() error {