很多修改

pull/1219/head
刘河 2019-01-26 17:27:28 +08:00
parent c34e5e1a7d
commit 0b90bf3a18
22 changed files with 433 additions and 357 deletions

124
README.md
View File

@ -1,7 +1,7 @@
# easyProxy # easyProxy
![](https://img.shields.io/github/stars/cnlh/easyProxy.svg) ![](https://img.shields.io/github/forks/cnlh/easyProxy.svg) ![](https://img.shields.io/github/license/cnlh/easyProxy.svg) ![](https://img.shields.io/github/stars/cnlh/easyProxy.svg) ![](https://img.shields.io/github/forks/cnlh/easyProxy.svg) ![](https://img.shields.io/github/license/cnlh/easyProxy.svg)
easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**可支持任何tcp、udp上层协议访问内网网站、本地支付接口调试、ssh访问、远程桌面内网dns解析等等……此外还**支持内网http代理、内网socks5代理**可实现在非内网环境下如同使用vpn一样访问内网资源和设备的效果,同时**支持socks5验证snnapy压缩节省带宽和流量、站点保护、加密传输、多路复用、host修改、自定义header** easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**可支持任何tcp、udp上层协议访问内网网站、本地支付接口调试、ssh访问、远程桌面内网dns解析等等……此外还**支持内网http代理、内网socks5代理**可实现在非内网环境下如同使用vpn一样访问内网资源和设备的效果。
目前市面上提供类似服务的有花生壳、TeamView、GoToMyCloud等等但要使用第三方的公网服务器就必须为第三方付费并且这些服务都有各种各样的限制此外由于数据包会流经第三方因此对数据安全也是一大隐患。 目前市面上提供类似服务的有花生壳、TeamView、GoToMyCloud等等但要使用第三方的公网服务器就必须为第三方付费并且这些服务都有各种各样的限制此外由于数据包会流经第三方因此对数据安全也是一大隐患。
@ -38,33 +38,47 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
- [x] 支持一个服务端,多个客户端模式 - [x] 支持一个服务端,多个客户端模式
- [x] host修改支持 - [x] host修改支持
- [x] 自定义设置header支持 - [x] 自定义设置header支持
- [x] 流量统计
- [x] 自动义404页面
- [x] 热更新支持
## 目录 ## 目录
1. [安装](#安装) * [安装](#安装)
2. [web管理模式](#web管理模式)(多隧道时推荐) * [编译安装](#源码安装)
3. [tcp隧道模式](#tcp隧道模式) * [release安装](#release安装)
4. [udp隧道模式](#udp隧道模式) * [web管理](#web管理模式)(多隧道时推荐)
5. [socks5代理模式](#socks5代理模式) * [启动](#启动)
6. [http代理模式](#http代理模式) * [配置文件说明](#服务端配置文件)
7. [数据压缩支持](#数据压缩支持) * 单隧道模式及介绍
8. [站点密码保护](#站点保护) * [tcp隧道模式](#tcp隧道模式)
9. [加密传输](#加密传输) * [udp隧道模式](#udp隧道模式)
10. [TCP多路复用](#多路复用) * [socks5代理模式](#socks5代理模式)
11. [host修改](#host修改) * [http代理模式](#http代理模式)
12. [自定义header](#自定义header)
13. [获取用户真实ip](#获取用户真实ip)
* [相关功能](#相关功能)
* [数据压缩支持](#数据压缩支持)
* [站点密码保护](#站点保护)
* [加密传输](#加密传输)
* [TCP多路复用](#多路复用)
* [host修改](#host修改)
* [自定义header](#自定义header)
* [获取用户真实ip](#获取用户真实ip)
* [热更新支持](#热更新支持)
* [客户端地址显示](#客户端地址显示)
* [自定义404页面](#404页面配置)
* [流量统计](#流量统计)
* [连接池](#连接池)
## 安装 ## 安装
1. release安装 ### release安装
> https://github.com/cnlh/easyProxy/releases > https://github.com/cnlh/easyProxy/releases
下载对应的系统版本即可服务端和客户端是单独的go语言开发无需任何第三方依赖 下载对应的系统版本即可服务端和客户端是单独的go语言开发无需任何第三方依赖
2. 源码安装 ### 源码安装
- 安装源码 - 安装源码(另有snappy、beego包)
> go get github.com/cnlh/easyProxy > go get github.com/cnlh/easyProxy
- 编译 - 编译
> go build cmd/server/proxy_server.go > go build cmd/server/proxy_server.go
@ -89,35 +103,7 @@ tcpport | 服务端客户端通信端口
**提示使用web模式时服务端执行文件必须在项目根目录否则无法正确加载配置文件** **提示使用web模式时服务端执行文件必须在项目根目录否则无法正确加载配置文件**
### 使用 ### 启动
**有两种模式:**
1、单客户端模式所有的隧道流量均从这个单客户端转发。
- 服务端
```
./proxy_server -vkey=DKibZF5TXvic1g3kY
```
名称 | 含义
---|---
vkey | 验证密钥
- 客户端
```
./proxy_client -server=ip:port -vkey=DKibZF5TXvic1g3kY
```
- 配置
进入web界面公网ip:web界面端口默认8080密码默认为123
2、多客户端模式不同的隧道流量均从不同的客户端转发。
- 服务端 - 服务端
@ -125,10 +111,11 @@ vkey | 验证密钥
``` ```
./proxy_server ./proxy_server
``` ```
名称 | 含义
---|---
mode | 运行模式
- 客户端 - 客户端
```
./proxy_server -server=ip:port -vkey=web界面中显示的
```
进入web管理界面有详细的命令 进入web管理界面有详细的命令
@ -316,30 +303,31 @@ httpport | http代理连接端口
配置HTTP代理即可ip为外网服务器ip端口为httpport即可在外网环境访问内网啦 配置HTTP代理即可ip为外网服务器ip端口为httpport即可在外网环境访问内网啦
``` ```
## 数据压缩支持 ## 相关功能
### 数据压缩支持
由于是内网穿透内网客户端与服务端之间的隧道存在大量的数据交换为节省流量加快传输速度由此本程序支持SNNAPY形式的压缩。 由于是内网穿透内网客户端与服务端之间的隧道存在大量的数据交换为节省流量加快传输速度由此本程序支持SNNAPY形式的压缩。
- 所有模式均支持数据压缩,可以与加密同时使用 - 所有模式均支持数据压缩,可以与加密同时使用
- 开启此功能会增加cpu和内存消耗
- 在server端加上参数 -compress=snappy或在web管理中设置 - 在server端加上参数 -compress=snappy或在web管理中设置
``` ```
-compress=snappy -compress=snappy
``` ```
## 加密传输 ### 加密传输
如果公司内网防火墙对外网访问进行了流量识别与屏蔽例如禁止了ssh协议等通过设置 配置文件,将服务端与客户端之间的通信内容加密传输,将会有效防止流量被拦截。 如果公司内网防火墙对外网访问进行了流量识别与屏蔽例如禁止了ssh协议等通过设置 配置文件,将服务端与客户端之间的通信内容加密传输,将会有效防止流量被拦截。
- 开启此功能会增加cpu和内存消耗
- 在server端加上参数 -crypt=true或在web管理中设置 - 在server端加上参数 -crypt=true或在web管理中设置
``` ```
-crypt=true -crypt=true
``` ```
## 多路复用 ### 多路复用
客户端和服务器端之间的连接支持多路复用,不再需要为每一个用户请求创建一个连接,使连接建立的延迟降低,并且避免了大量文件描述符的占用。 客户端和服务器端之间的连接支持多路复用,不再需要为每一个用户请求创建一个连接,使连接建立的延迟降低,并且避免了大量文件描述符的占用。
@ -351,7 +339,7 @@ httpport | http代理连接端口
``` ```
## 站点保护 ### 站点保护
由于所有客户端共用一个 http 服务端口,任何知道你的域名和 url 的人都能访问到你部署在内网的 web 服务,但是在某些场景下需要确保只有限定的用户才能访问。 由于所有客户端共用一个 http 服务端口,任何知道你的域名和 url 的人都能访问到你部署在内网的 web 服务,但是在某些场景下需要确保只有限定的用户才能访问。
easyProxy支持通过 HTTP Basic Auth 来保护你的 web 服务,使用户需要通过用户名和密码才能访问到你的服务。 easyProxy支持通过 HTTP Basic Auth 来保护你的 web 服务,使用户需要通过用户名和密码才能访问到你的服务。
@ -361,25 +349,37 @@ easyProxy支持通过 HTTP Basic Auth 来保护你的 web 服务,使用户需
-u=user -p=password -u=user -p=password
``` ```
web管理中也可配置 - web管理中也可配置
## host修改 ### host修改
通常情况下本代理不会修改转发的任何数据。但有一些后端服务会根据 http 请求 header 中的 host 字段来展现不同的网站,例如 nginx 的虚拟主机服务,启用 host-header 的修改功能可以动态修改 http 请求中的 host 字段。该功能仅限于域名代理模式。 通常情况下本代理不会修改转发的任何数据。但有一些后端服务会根据 http 请求 header 中的 host 字段来展现不同的网站,例如 nginx 的虚拟主机服务,启用 host-header 的修改功能可以动态修改 http 请求中的 host 字段。该功能仅限于域名代理模式。
**使用方法在web管理中设置** **使用方法在web管理中设置**
## 自定义header ### 自定义header
支持对header进行新增或者修改以配合服务的需要 支持对header进行新增或者修改以配合服务的需要
## 获取用户真实ip ### 获取用户真实ip
目前只有域名模式的代理支持这一功能,可以通过用户请求的 header 中的 X-Forwarded-For 和 X-Real-IP 来获取用户真实 IP。 目前只有域名模式的代理支持这一功能,可以通过用户请求的 header 中的 X-Forwarded-For 和 X-Real-IP 来获取用户真实 IP。
**本代理前会在每一个请求中添加了这两个 header。** **本代理前会在每一个请求中添加了这两个 header。**
### 热更新支持
在web管理中的修改将实时使用无需重启客户端或者服务端
### 客户端地址显示
在web管理中将显示客户端的连接地址
### 404页面配置
支持域名解析模式的自定义404页面修改/web/static/page/error.html中内容即可暂不支持静态文件等内容
### 流量统计
可统计显示每个代理使用的流量,由于压缩和加密等原因,会和实际环境中的略有差异
### 连接池
easyProxy会预先和后端服务建立起指定数量的连接每次接收到用户请求后会从连接池中取出一个连接和用户连接关联起来避免了等待与后端服务建立连接时间。
## 操作系统支持
支持Windows、Linux、MacOSX等无第三方依赖库。

View File

@ -31,7 +31,7 @@ func newList() *list {
return l return l
} }
type Tunnel struct { type Bridge struct {
TunnelPort int //通信隧道端口 TunnelPort int //通信隧道端口
listener *net.TCPListener //server端监听 listener *net.TCPListener //server端监听
SignalList map[int]*list //通信 SignalList map[int]*list //通信
@ -41,8 +41,8 @@ type Tunnel struct {
tunnelLock sync.Mutex tunnelLock sync.Mutex
} }
func NewTunnel(tunnelPort int, runList map[int]interface{}) *Tunnel { func NewTunnel(tunnelPort int, runList map[int]interface{}) *Bridge {
t := new(Tunnel) t := new(Bridge)
t.TunnelPort = tunnelPort t.TunnelPort = tunnelPort
t.SignalList = make(map[int]*list) t.SignalList = make(map[int]*list)
t.TunnelList = make(map[int]*list) t.TunnelList = make(map[int]*list)
@ -50,7 +50,7 @@ func NewTunnel(tunnelPort int, runList map[int]interface{}) *Tunnel {
return t return t
} }
func (s *Tunnel) StartTunnel() error { func (s *Bridge) StartTunnel() error {
var err error var err error
s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.TunnelPort, ""}) s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.TunnelPort, ""})
if err != nil { if err != nil {
@ -61,7 +61,7 @@ func (s *Tunnel) StartTunnel() error {
} }
//tcp server //tcp server
func (s *Tunnel) tunnelProcess() error { func (s *Bridge) tunnelProcess() error {
var err error var err error
for { for {
conn, err := s.listener.Accept() conn, err := s.listener.Accept()
@ -75,12 +75,12 @@ func (s *Tunnel) tunnelProcess() error {
} }
//验证失败返回错误验证flag并且关闭连接 //验证失败返回错误验证flag并且关闭连接
func (s *Tunnel) verifyError(c *utils.Conn) { func (s *Bridge) verifyError(c *utils.Conn) {
c.Conn.Write([]byte(utils.VERIFY_EER)) c.Conn.Write([]byte(utils.VERIFY_EER))
c.Conn.Close() c.Conn.Close()
} }
func (s *Tunnel) cliProcess(c *utils.Conn) error { func (s *Bridge) cliProcess(c *utils.Conn) error {
c.Conn.(*net.TCPConn).SetReadDeadline(time.Now().Add(time.Duration(5) * time.Second)) c.Conn.(*net.TCPConn).SetReadDeadline(time.Now().Add(time.Duration(5) * time.Second))
vval := make([]byte, 32) vval := make([]byte, 32)
if _, err := c.Conn.Read(vval); err != nil { if _, err := c.Conn.Read(vval); err != nil {
@ -104,7 +104,7 @@ func (s *Tunnel) cliProcess(c *utils.Conn) error {
} }
//tcp连接类型区分 //tcp连接类型区分
func (s *Tunnel) typeDeal(typeVal string, c *utils.Conn, id int) error { func (s *Bridge) typeDeal(typeVal string, c *utils.Conn, id int) error {
switch typeVal { switch typeVal {
case utils.WORK_MAIN: case utils.WORK_MAIN:
log.Println("客户端连接成功", c.Conn.RemoteAddr()) log.Println("客户端连接成功", c.Conn.RemoteAddr())
@ -119,7 +119,7 @@ func (s *Tunnel) typeDeal(typeVal string, c *utils.Conn, id int) error {
} }
//加到对应的list中 //加到对应的list中
func (s *Tunnel) addList(m map[int]*list, c *utils.Conn, id int) { func (s *Bridge) addList(m map[int]*list, c *utils.Conn, id int) {
s.lock.Lock() s.lock.Lock()
if v, ok := m[id]; ok { if v, ok := m[id]; ok {
v.Add(c) v.Add(c)
@ -132,7 +132,7 @@ func (s *Tunnel) addList(m map[int]*list, c *utils.Conn, id int) {
} }
//新建隧道 //新建隧道
func (s *Tunnel) newChan(id int) error { func (s *Bridge) newChan(id int) error {
var connPass *utils.Conn var connPass *utils.Conn
var err error var err error
retry: retry:
@ -148,7 +148,7 @@ retry:
//得到一个tcp隧道 //得到一个tcp隧道
//TODO 超时问题 锁机制问题 对单个客户端加锁 //TODO 超时问题 锁机制问题 对单个客户端加锁
func (s *Tunnel) GetTunnel(id int, en, de int, crypt, mux bool) (c *utils.Conn, err error) { func (s *Bridge) GetTunnel(id int, en, de int, crypt, mux bool) (c *utils.Conn, err error) {
retry: retry:
if c, err = s.waitAndPop(s.TunnelList, id); err != nil { if c, err = s.waitAndPop(s.TunnelList, id); err != nil {
return return
@ -162,7 +162,7 @@ retry:
} }
//得到一个通信通道 //得到一个通信通道
func (s *Tunnel) GetSignal(id int) (err error, conn *utils.Conn) { func (s *Bridge) GetSignal(id int) (err error, conn *utils.Conn) {
if v, ok := s.SignalList[id]; !ok || v.Len() == 0 { if v, ok := s.SignalList[id]; !ok || v.Len() == 0 {
err = errors.New("客户端未连接") err = errors.New("客户端未连接")
return return
@ -172,14 +172,14 @@ func (s *Tunnel) GetSignal(id int) (err error, conn *utils.Conn) {
} }
//重回slice 复用 //重回slice 复用
func (s *Tunnel) ReturnSignal(conn *utils.Conn, id int) { func (s *Bridge) ReturnSignal(conn *utils.Conn, id int) {
if v, ok := s.SignalList[id]; ok { if v, ok := s.SignalList[id]; ok {
v.Add(conn) v.Add(conn)
} }
} }
//重回slice 复用 //重回slice 复用
func (s *Tunnel) ReturnTunnel(conn *utils.Conn, id int) { func (s *Bridge) ReturnTunnel(conn *utils.Conn, id int) {
if v, ok := s.TunnelList[id]; ok { if v, ok := s.TunnelList[id]; ok {
utils.FlushConn(conn.Conn) utils.FlushConn(conn.Conn)
v.Add(conn) v.Add(conn)
@ -187,16 +187,16 @@ func (s *Tunnel) ReturnTunnel(conn *utils.Conn, id int) {
} }
//删除通信通道 //删除通信通道
func (s *Tunnel) DelClientSignal(id int) { func (s *Bridge) DelClientSignal(id int) {
s.delClient(id, s.SignalList) s.delClient(id, s.SignalList)
} }
//删除隧道 //删除隧道
func (s *Tunnel) DelClientTunnel(id int) { func (s *Bridge) DelClientTunnel(id int) {
s.delClient(id, s.TunnelList) s.delClient(id, s.TunnelList)
} }
func (s *Tunnel) delClient(id int, l map[int]*list) { func (s *Bridge) delClient(id int, l map[int]*list) {
if t := l[id]; t != nil { if t := l[id]; t != nil {
for { for {
if t.Len() <= 0 { if t.Len() <= 0 {
@ -209,7 +209,7 @@ func (s *Tunnel) delClient(id int, l map[int]*list) {
} }
//等待 //等待
func (s *Tunnel) waitAndPop(m map[int]*list, id int) (c *utils.Conn, err error) { func (s *Bridge) waitAndPop(m map[int]*list, id int) (c *utils.Conn, err error) {
ticker := time.NewTicker(time.Millisecond * 100) ticker := time.NewTicker(time.Millisecond * 100)
stop := time.After(time.Second * 3) stop := time.After(time.Second * 3)
for { for {
@ -231,7 +231,7 @@ func (s *Tunnel) waitAndPop(m map[int]*list, id int) (c *utils.Conn, err error)
return return
} }
func (s *Tunnel) verify(id int) bool { func (s *Bridge) verify(id int) bool {
for k := range s.RunList { for k := range s.RunList {
if k == id { if k == id {
return true return true

View File

@ -24,22 +24,32 @@ var (
func main() { func main() {
flag.Parse() flag.Parse()
server.VerifyKey = *VerifyKey task := &utils.Tunnel{
cnf := &utils.ServerConfig{ TcpPort: *httpPort,
TcpPort: *httpPort, Mode: *rpMode,
Mode: *rpMode, Target: *tunnelTarget,
Target: *tunnelTarget, Config: &utils.Config{
VerifyKey: *VerifyKey, U: *u,
U: *u, P: *p,
P: *p, Compress: *compress,
Compress: *compress, Crypt: utils.GetBoolByStr(*crypt),
Start: 0, Mux: utils.GetBoolByStr(*mux),
IsRun: 0, },
ClientStatus: 0, Flow: &utils.Flow{},
Crypt: utils.GetBoolByStr(*crypt), UseClientCnf: false,
Mux: utils.GetBoolByStr(*mux), }
CompressEncode: 0, if *VerifyKey != "" {
CompressDecode: 0, c := &utils.Client{
Id: 0,
VerifyKey: *VerifyKey,
Addr: "",
Remark: "",
Status: true,
IsConnect: false,
}
c.Cnf.CompressDecode, c.Cnf.CompressEncode = utils.GetCompressType(c.Cnf.Compress)
server.CsvDb.Clients[0] = c
task.Client = c
} }
if *TcpPort == 0 { if *TcpPort == 0 {
p, err := beego.AppConfig.Int("tcpport") p, err := beego.AppConfig.Int("tcpport")
@ -50,6 +60,6 @@ func main() {
} }
} }
log.Println("服务端启动监听tcp服务端端口", *TcpPort) log.Println("服务端启动监听tcp服务端端口", *TcpPort)
cnf.CompressDecode, cnf.CompressEncode = utils.GetCompressType(cnf.Compress) task.Config.CompressDecode, task.Config.CompressEncode = utils.GetCompressType(task.Config.Compress)
server.StartNewServer(*TcpPort, cnf) server.StartNewServer(*TcpPort, task)
} }

View File

@ -1,2 +1,2 @@
2,zl4p3da659qa9rh3,127.0.0.1:58000,测试2,true,,,0,0,
1,rfd0tl1anega0d0g,127.0.0.1:53603,测试,true,1,1,1,1,snappy 1,rfd0tl1anega0d0g,127.0.0.1:53603,测试,true,1,1,1,1,snappy
2,zl4p3da659qa9rh3,127.0.0.1:52096,测试2,true,1,1,1,1,snappy

1 2 1 zl4p3da659qa9rh3 rfd0tl1anega0d0g 127.0.0.1:58000 127.0.0.1:53603 测试2 测试 true 1 1 0 1 0 1 snappy
2 zl4p3da659qa9rh3 127.0.0.1:58000 测试2 true 0 0
1 1 1 rfd0tl1anega0d0g rfd0tl1anega0d0g 127.0.0.1:53603 127.0.0.1:53603 测试 测试 true 1 1 1 1 1 1 1 1 snappy snappy
2 2 zl4p3da659qa9rh3 127.0.0.1:52096 测试2 true 1 1 1 1 snappy

View File

@ -1,2 +1,2 @@
a.o.com,127.0.0.1:8080,1,,,测试2
b.o.com,127.0.0.1:8082,2,,,测试 b.o.com,127.0.0.1:8082,2,,,测试
a.o.com,127.0.0.1:8080,1,Connection: close,,测试2

1 a.o.com b.o.com 127.0.0.1:8080 127.0.0.1:8082 1 2 测试2 测试
a.o.com 127.0.0.1:8080 1 测试2
1 b.o.com b.o.com 127.0.0.1:8082 127.0.0.1:8082 2 2 测试 测试
2 a.o.com 127.0.0.1:8080 1 Connection: close 测试2

View File

@ -1,4 +1,5 @@
9001,tunnelServer,127.0.0.1:8080,,,,1,0,0,0,0,1,1,true,test 53,udpServer,114.114.114.114:53,,,,1,0,0,0,1,2,2,true,udp测试
53,udpServer,114.114.114.114:53,,,,1,0,0,0,0,2,2,true,udp测试 9001,tunnelServer,127.0.0.1:8080,1,1,snappy,1,1,1,0,0,1,1,false,test
8024,socks5Server,,,,,1,0,0,0,0,3,2,true,socks5测试 9009,tunnelServer,127.0.0.1:5900,,,,1,0,0,0,0,5,2,true,vnc
8025,httpProxyServer,,,,,1,0,0,0,0,4,2,true,http测试 8025,httpProxyServer,,2,2,snappy,1,1,1,0,0,4,2,false,http测试
8024,socks5Server,,,,,1,0,0,0,0,3,2,false,socks5测试

1 9001 53 tunnelServer udpServer 127.0.0.1:8080 114.114.114.114:53 1 0 0 0 0 1 2 1 2 true test udp测试
2 53 9001 udpServer tunnelServer 114.114.114.114:53 127.0.0.1:8080 1 1 snappy 1 0 1 0 1 0 0 2 0 1 2 1 true false udp测试 test
3 8024 9009 socks5Server tunnelServer 127.0.0.1:5900 1 0 0 0 0 3 0 5 2 2 true socks5测试 vnc
4 8025 8025 httpProxyServer httpProxyServer 2 2 snappy 1 0 1 0 1 0 0 4 0 4 2 2 true false http测试 http测试
5 8024 socks5Server 1 0 0 0 0 3 2 false socks5测试

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 KiB

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

After

Width:  |  Height:  |  Size: 281 KiB

View File

@ -8,53 +8,47 @@ import (
//server base struct //server base struct
type server struct { type server struct {
bridge *bridge.Tunnel bridge *bridge.Bridge
config *utils.ServerConfig task *utils.Tunnel
config *utils.Config
sync.Mutex sync.Mutex
} }
func (s *server) GetTunnelAndWriteHost(connType string, cnf *utils.ServerConfig, addr string) (*utils.Conn, error) { func (s *server) GetTunnelAndWriteHost(connType string, clientId int, cnf *utils.Config, addr string) (link *utils.Conn, err error) {
var err error if link, err = s.bridge.GetTunnel(clientId, cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, cnf.Mux); err != nil {
link, err := s.bridge.GetTunnel(cnf.ClientId, cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, cnf.Mux) return
if err != nil {
return nil, err
} }
if _, err = link.WriteHost(connType, addr); err != nil { if _, err = link.WriteHost(connType, addr); err != nil {
link.Close() link.Close()
return nil, err
} }
return link, nil return
} }
func (s *server) FlowAdd(in, out int64) { func (s *server) FlowAdd(in, out int64) {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
if s.config.Flow == nil { s.task.Flow.ExportFlow += out
s.config.Flow = new(utils.Flow) s.task.Flow.InletFlow += in
}
s.config.Flow.ExportFlow += out
s.config.Flow.InletFlow += in
} }
func (s *server) FlowAddHost(host *utils.HostList, in, out int64) { func (s *server) FlowAddHost(host *utils.Host, in, out int64) {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
if s.config.Flow == nil {
s.config.Flow = new(utils.Flow)
}
host.Flow.ExportFlow += out host.Flow.ExportFlow += out
host.Flow.InletFlow += in host.Flow.InletFlow += in
} }
//热更新配置 //热更新配置
func (s *server) ResetConfig() { func (s *server) ResetConfig() {
task, err := CsvDb.GetTask(s.config.Id) //获取最新数据
task, err := CsvDb.GetTask(s.task.Id)
if err != nil { if err != nil {
return return
} }
s.config.UseClientCnf = task.UseClientCnf s.task.UseClientCnf = task.UseClientCnf
if s.config.UseClientCnf { //使用客户端配置
client, err := CsvDb.GetClient(s.config.ClientId) if s.task.UseClientCnf {
client, err := CsvDb.GetClient(s.task.Client.Id)
if err == nil { if err == nil {
s.config.U = client.Cnf.U s.config.U = client.Cnf.U
s.config.P = client.Cnf.P s.config.P = client.Cnf.P
@ -62,15 +56,14 @@ func (s *server) ResetConfig() {
s.config.Mux = client.Cnf.Mux s.config.Mux = client.Cnf.Mux
s.config.Crypt = client.Cnf.Crypt s.config.Crypt = client.Cnf.Crypt
} }
s.config.CompressDecode, s.config.CompressEncode = utils.GetCompressType(client.Cnf.Compress)
} else { } else {
if err == nil { if err == nil {
s.config.U = task.U s.config.U = task.Config.U
s.config.P = task.P s.config.P = task.Config.P
s.config.Compress = task.Compress s.config.Compress = task.Config.Compress
s.config.Mux = task.Mux s.config.Mux = task.Config.Mux
s.config.Crypt = task.Crypt s.config.Crypt = task.Config.Crypt
} }
s.config.CompressDecode, s.config.CompressEncode = utils.GetCompressType(task.Compress)
} }
s.config.CompressDecode, s.config.CompressEncode = utils.GetCompressType(s.config.Compress)
} }

View File

@ -13,13 +13,7 @@ type process func(c *utils.Conn, s *TunnelModeServer) error
//tcp隧道模式 //tcp隧道模式
func ProcessTunnel(c *utils.Conn, s *TunnelModeServer) error { func ProcessTunnel(c *utils.Conn, s *TunnelModeServer) error {
_, _, rb, err, r := c.GetHost() return s.dealClient(c, s.config, s.task.Target, "", nil)
if err == nil {
if err := s.auth(r, c, s.config.U, s.config.P); err != nil {
return err
}
}
return s.dealClient(c, s.config, s.config.Target, "", rb)
} }
//http代理模式 //http代理模式
@ -41,8 +35,7 @@ func ProcessHost(c *utils.Conn, s *TunnelModeServer) error {
var ( var (
isConn = true isConn = true
link *utils.Conn link *utils.Conn
client *utils.Client host *utils.Host
host *utils.HostList
wg sync.WaitGroup wg sync.WaitGroup
) )
for { for {
@ -52,17 +45,17 @@ func ProcessHost(c *utils.Conn, s *TunnelModeServer) error {
} }
//首次获取conn //首次获取conn
if isConn { if isConn {
if host, client, err = GetKeyByHost(r.Host); err != nil { if host, err = GetInfoByHost(r.Host); err != nil {
log.Printf("the host %s is not found !", r.Host) log.Printf("the host %s is not found !", r.Host)
break break
} }
client.Cnf.ClientId = host.ClientId host.Client.Cnf.CompressDecode, host.Client.Cnf.CompressEncode = utils.GetCompressType(host.Client.Cnf.Compress)
client.Cnf.CompressDecode, client.Cnf.CompressEncode = utils.GetCompressType(client.Cnf.Compress)
if err = s.auth(r, c, client.Cnf.U, client.Cnf.P); err != nil { if err = s.auth(r, c, host.Client.Cnf.U, host.Client.Cnf.P); err != nil {
break break
} }
if link, err = s.GetTunnelAndWriteHost(utils.CONN_TCP, client.Cnf, host.Target); err != nil { if link, err = s.GetTunnelAndWriteHost(utils.CONN_TCP, host.Client.Id, host.Client.Cnf, host.Target); err != nil {
log.Println("get bridge tunnel error: ", err) log.Println("get bridge tunnel error: ", err)
break break
} }
@ -72,27 +65,28 @@ func ProcessHost(c *utils.Conn, s *TunnelModeServer) error {
} else { } else {
wg.Add(1) wg.Add(1)
go func() { go func() {
out, _ := utils.Relay(c.Conn, link.Conn, client.Cnf.CompressDecode, client.Cnf.Crypt, client.Cnf.Mux) out, _ := utils.Relay(c.Conn, link.Conn, host.Client.Cnf.CompressDecode, host.Client.Cnf.Crypt, host.Client.Cnf.Mux)
wg.Done() wg.Done()
s.FlowAddHost(host, 0, out) s.FlowAddHost(host, 0, out)
}() }()
} }
isConn = false isConn = false
} }
//根据设定修改header和host
utils.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String()) utils.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String())
b, err := httputil.DumpRequest(r, true) b, err := httputil.DumpRequest(r, true)
s.FlowAddHost(host, int64(len(b)), 0)
if err != nil { if err != nil {
break break
} }
if _, err := link.WriteTo(b, client.Cnf.CompressEncode, client.Cnf.Crypt); err != nil { s.FlowAddHost(host, int64(len(b)), 0)
if _, err := link.WriteTo(b, host.Client.Cnf.CompressEncode, host.Client.Cnf.Crypt); err != nil {
break break
} }
} }
wg.Wait() wg.Wait()
if client != nil && client.Cnf != nil && client.Cnf.Mux && link != nil { if host != nil && host.Client.Cnf != nil && host.Client.Cnf.Mux && link != nil {
link.WriteTo([]byte(utils.IO_EOF), client.Cnf.CompressEncode, client.Cnf.Crypt) link.WriteTo([]byte(utils.IO_EOF), host.Client.Cnf.CompressEncode, host.Client.Cnf.Crypt)
s.bridge.ReturnTunnel(link, client.Id) s.bridge.ReturnTunnel(link, host.Client.Id)
} else if link != nil { } else if link != nil {
link.Close() link.Close()
} }
@ -103,5 +97,3 @@ func ProcessHost(c *utils.Conn, s *TunnelModeServer) error {
c.Close() c.Close()
return nil return nil
} }

View File

@ -20,10 +20,9 @@ type RunServer struct {
} }
var ( var (
Bridge *bridge.Tunnel Bridge *bridge.Bridge
RunList map[int]interface{} //运行中的任务 RunList map[int]interface{} //运行中的任务
CsvDb = utils.GetCsvDb() CsvDb = utils.GetCsvDb()
VerifyKey string
) )
func init() { func init() {
@ -33,7 +32,7 @@ func init() {
//从csv文件中恢复任务 //从csv文件中恢复任务
func InitFromCsv() { func InitFromCsv() {
for _, v := range CsvDb.Tasks { for _, v := range CsvDb.Tasks {
if v.Start == 1 { if v.Status {
log.Println("启动模式:", v.Mode, "监听端口:", v.TcpPort) log.Println("启动模式:", v.Mode, "监听端口:", v.TcpPort)
AddTask(v) AddTask(v)
} }
@ -41,7 +40,7 @@ func InitFromCsv() {
} }
//start a new server //start a new server
func StartNewServer(bridgePort int, cnf *utils.ServerConfig) { func StartNewServer(bridgePort int, cnf *utils.Tunnel) {
Bridge = bridge.NewTunnel(bridgePort, RunList) Bridge = bridge.NewTunnel(bridgePort, RunList)
if err := Bridge.StartTunnel(); err != nil { if err := Bridge.StartTunnel(); err != nil {
log.Fatalln("服务端开启失败", err) log.Fatalln("服务端开启失败", err)
@ -58,37 +57,32 @@ func StartNewServer(bridgePort int, cnf *utils.ServerConfig) {
} }
//new a server by mode name //new a server by mode name
func NewMode(Bridge *bridge.Tunnel, c *utils.ServerConfig) interface{} { func NewMode(Bridge *bridge.Bridge, c *utils.Tunnel) interface{} {
config := utils.DeepCopyConfig(c) switch c.Mode {
switch config.Mode {
case "tunnelServer": case "tunnelServer":
return NewTunnelModeServer(ProcessTunnel, Bridge, config) return NewTunnelModeServer(ProcessTunnel, Bridge, c)
case "socks5Server": case "socks5Server":
return NewSock5ModeServer(Bridge, config) return NewSock5ModeServer(Bridge, c)
case "httpProxyServer": case "httpProxyServer":
return NewTunnelModeServer(ProcessHttp, Bridge, config) return NewTunnelModeServer(ProcessHttp, Bridge, c)
case "udpServer": case "udpServer":
return NewUdpModeServer(Bridge, config) return NewUdpModeServer(Bridge, c)
case "webServer": case "webServer":
InitFromCsv() InitFromCsv()
p, _ := beego.AppConfig.Int("hostPort") p, _ := beego.AppConfig.Int("hostPort")
t := &utils.ServerConfig{ t := &utils.Tunnel{
TcpPort: p, TcpPort: p,
Mode: "httpHostServer", Mode: "httpHostServer",
Target: "", Target: "",
U: "", Config: &utils.Config{},
P: "", Status: true,
Compress: "",
Start: 1,
IsRun: 0,
ClientStatus: 0,
} }
AddTask(t) AddTask(t)
return NewWebServer(Bridge) return NewWebServer(Bridge)
case "hostServer": case "hostServer":
return NewHostServer(config) return NewHostServer(c)
case "httpHostServer": case "httpHostServer":
return NewTunnelModeServer(ProcessHost, Bridge, config) return NewTunnelModeServer(ProcessHost, Bridge, c)
} }
return nil return nil
} }
@ -100,7 +94,7 @@ func StopServer(id int) error {
if t, err := CsvDb.GetTask(id); err != nil { if t, err := CsvDb.GetTask(id); err != nil {
return err return err
} else { } else {
t.Start = 0 t.Status = false
CsvDb.UpdateTask(t) CsvDb.UpdateTask(t)
} }
return nil return nil
@ -109,7 +103,7 @@ func StopServer(id int) error {
} }
//add task //add task
func AddTask(t *utils.ServerConfig) error { func AddTask(t *utils.Tunnel) error {
if svr := NewMode(Bridge, t); svr != nil { if svr := NewMode(Bridge, t); svr != nil {
RunList[t.Id] = svr RunList[t.Id] = svr
go func() { go func() {
@ -131,7 +125,7 @@ func StartTask(id int) error {
return err return err
} else { } else {
AddTask(t) AddTask(t)
t.Start = 1 t.Status = true
CsvDb.UpdateTask(t) CsvDb.UpdateTask(t)
} }
return nil return nil
@ -146,12 +140,11 @@ func DelTask(id int) error {
} }
//get key by host from x //get key by host from x
func GetKeyByHost(host string) (h *utils.HostList, t *utils.Client, err error) { func GetInfoByHost(host string) (h *utils.Host, err error) {
for _, v := range CsvDb.Hosts { for _, v := range CsvDb.Hosts {
s := strings.Split(host, ":") s := strings.Split(host, ":")
if s[0] == v.Host { if s[0] == v.Host {
h = v h = v
t, err = CsvDb.GetClient(v.ClientId)
return return
} }
} }
@ -160,39 +153,25 @@ func GetKeyByHost(host string) (h *utils.HostList, t *utils.Client, err error) {
} }
//get task list by page num //get task list by page num
func GetServerConfig(start, length int, typeVal string, clientId int) ([]*utils.ServerConfig, int) { func GetTunnel(start, length int, typeVal string, clientId int) ([]*utils.Tunnel, int) {
list := make([]*utils.ServerConfig, 0) list := make([]*utils.Tunnel, 0)
var cnt int var cnt int
for _, v := range CsvDb.Tasks { for _, v := range CsvDb.Tasks {
if (typeVal != "" && v.Mode != typeVal) || (typeVal == "" && clientId != v.ClientId) { if (typeVal != "" && v.Mode != typeVal) || (typeVal == "" && clientId != v.Client.Id) {
continue continue
} }
if v.UseClientCnf {
v = utils.DeepCopyConfig(v)
if c, err := CsvDb.GetClient(v.ClientId); err == nil {
v.Compress = c.Cnf.Compress
v.Mux = c.Cnf.Mux
v.Crypt = c.Cnf.Crypt
v.U = c.Cnf.U
v.P = c.Cnf.P
}
}
cnt++ cnt++
if _, ok := Bridge.SignalList[v.Client.Id]; ok {
v.Client.IsConnect = true
} else {
v.Client.IsConnect = false
}
if start--; start < 0 { if start--; start < 0 {
if length--; length > 0 { if length--; length > 0 {
if _, ok := RunList[v.Id]; ok { if _, ok := RunList[v.Id]; ok {
v.IsRun = 1 v.Client.Status = true
} else { } else {
v.IsRun = 0 v.Client.Status = false
}
if s, ok := Bridge.SignalList[v.ClientId]; ok {
if s.Len() > 0 {
v.ClientStatus = 1
} else {
v.ClientStatus = 0
}
} else {
v.ClientStatus = 0
} }
list = append(list, v) list = append(list, v)
} }
@ -218,13 +197,13 @@ func dealClientData(list []*utils.Client) {
v.Flow.InletFlow = 0 v.Flow.InletFlow = 0
v.Flow.ExportFlow = 0 v.Flow.ExportFlow = 0
for _, h := range CsvDb.Hosts { for _, h := range CsvDb.Hosts {
if h.ClientId == v.Id { if h.Client.Id == v.Id {
v.Flow.InletFlow += h.Flow.InletFlow v.Flow.InletFlow += h.Flow.InletFlow
v.Flow.ExportFlow += h.Flow.ExportFlow v.Flow.ExportFlow += h.Flow.ExportFlow
} }
} }
for _, t := range CsvDb.Tasks { for _, t := range CsvDb.Tasks {
if t.ClientId == v.Id { if t.Client.Id == v.Id {
v.Flow.InletFlow += t.Flow.InletFlow v.Flow.InletFlow += t.Flow.InletFlow
v.Flow.ExportFlow += t.Flow.ExportFlow v.Flow.ExportFlow += t.Flow.ExportFlow
} }
@ -236,12 +215,12 @@ func dealClientData(list []*utils.Client) {
//根据客户端id删除其所属的所有隧道和域名 //根据客户端id删除其所属的所有隧道和域名
func DelTunnelAndHostByClientId(clientId int) { func DelTunnelAndHostByClientId(clientId int) {
for _, v := range CsvDb.Tasks { for _, v := range CsvDb.Tasks {
if v.ClientId == clientId { if v.Client.Id == clientId {
DelTask(v.Id) DelTask(v.Id)
} }
} }
for _, v := range CsvDb.Hosts { for _, v := range CsvDb.Hosts {
if v.ClientId == clientId { if v.Client.Id == clientId {
CsvDb.DelHost(v.Host) CsvDb.DelHost(v.Host)
} }
} }

View File

@ -141,7 +141,7 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *utils
} else { } else {
ltype = utils.CONN_TCP ltype = utils.CONN_TCP
} }
if proxyConn, err = s.GetTunnelAndWriteHost(ltype, s.config, addr); err != nil { if proxyConn, err = s.GetTunnelAndWriteHost(ltype, s.task.Client.Id, s.config, addr); err != nil {
log.Println("get bridge tunnel error: ", err) log.Println("get bridge tunnel error: ", err)
return return
} }
@ -160,7 +160,7 @@ func (s *Sock5ModeServer) handleConnect(c net.Conn) {
proxyConn, err := s.doConnect(c, connectMethod) proxyConn, err := s.doConnect(c, connectMethod)
defer func() { defer func() {
if s.config.Mux && proxyConn != nil { if s.config.Mux && proxyConn != nil {
s.bridge.ReturnTunnel(proxyConn, s.config.ClientId) s.bridge.ReturnTunnel(proxyConn, s.task.Client.Id)
} }
}() }()
if err != nil { if err != nil {
@ -198,7 +198,7 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) {
proxyConn, err := s.doConnect(c, associateMethod) proxyConn, err := s.doConnect(c, associateMethod)
defer func() { defer func() {
if s.config.Mux && proxyConn != nil { if s.config.Mux && proxyConn != nil {
s.bridge.ReturnTunnel(proxyConn, s.config.ClientId) s.bridge.ReturnTunnel(proxyConn, s.task.Client.Id)
} }
}() }()
if err != nil { if err != nil {
@ -285,7 +285,7 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error {
//start //start
func (s *Sock5ModeServer) Start() error { func (s *Sock5ModeServer) Start() error {
var err error var err error
s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.config.TcpPort)) s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.task.TcpPort))
if err != nil { if err != nil {
return err return err
} }
@ -309,10 +309,11 @@ func (s *Sock5ModeServer) Close() error {
} }
//new //new
func NewSock5ModeServer(bridge *bridge.Tunnel, cnf *utils.ServerConfig) *Sock5ModeServer { func NewSock5ModeServer(bridge *bridge.Bridge, task *utils.Tunnel) *Sock5ModeServer {
s := new(Sock5ModeServer) s := new(Sock5ModeServer)
s.bridge = bridge s.bridge = bridge
s.config = cnf s.task = task
s.config = utils.DeepCopyConfig(task.Config)
if s.config.U != "" && s.config.P != "" { if s.config.U != "" && s.config.P != "" {
s.isVerify = true s.isVerify = true
} else { } else {

View File

@ -20,11 +20,12 @@ type TunnelModeServer struct {
} }
//tcp|http|host //tcp|http|host
func NewTunnelModeServer(process process, bridge *bridge.Tunnel, cnf *utils.ServerConfig) *TunnelModeServer { func NewTunnelModeServer(process process, bridge *bridge.Bridge, task *utils.Tunnel) *TunnelModeServer {
s := new(TunnelModeServer) s := new(TunnelModeServer)
s.bridge = bridge s.bridge = bridge
s.process = process s.process = process
s.config = cnf s.task = task
s.config = utils.DeepCopyConfig(task.Config)
return s return s
} }
@ -34,7 +35,7 @@ func (s *TunnelModeServer) Start() error {
if s.errorContent, err = utils.ReadAllFromFile(beego.AppPath + "/web/static/page/error.html"); err != nil { if s.errorContent, err = utils.ReadAllFromFile(beego.AppPath + "/web/static/page/error.html"); err != nil {
s.errorContent = []byte("easyProxy 404") s.errorContent = []byte("easyProxy 404")
} }
s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.config.TcpPort, ""}) s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.task.TcpPort, ""})
if err != nil { if err != nil {
return err return err
} }
@ -69,15 +70,15 @@ func (s *TunnelModeServer) writeConnFail(c net.Conn) {
} }
//与客户端建立通道 //与客户端建立通道
func (s *TunnelModeServer) dealClient(c *utils.Conn, cnf *utils.ServerConfig, addr string, method string, rb []byte) error { func (s *TunnelModeServer) dealClient(c *utils.Conn, cnf *utils.Config, addr string, method string, rb []byte) error {
var link *utils.Conn var link *utils.Conn
var err error var err error
defer func() { defer func() {
if cnf.Mux && link != nil { if cnf.Mux && link != nil {
s.bridge.ReturnTunnel(link, cnf.ClientId) s.bridge.ReturnTunnel(link, s.task.Client.Id)
} }
}() }()
if link, err = s.GetTunnelAndWriteHost(utils.CONN_TCP, cnf, addr); err != nil { if link, err = s.GetTunnelAndWriteHost(utils.CONN_TCP, s.task.Client.Id, cnf, addr); err != nil {
log.Println("get bridge tunnel error: ", err) log.Println("get bridge tunnel error: ", err)
return err return err
} }
@ -115,7 +116,7 @@ func (s *WebServer) Start() {
} }
//new //new
func NewWebServer(bridge *bridge.Tunnel) *WebServer { func NewWebServer(bridge *bridge.Bridge) *WebServer {
s := new(WebServer) s := new(WebServer)
s.bridge = bridge s.bridge = bridge
return s return s
@ -131,9 +132,10 @@ func (s *HostServer) Start() error {
return nil return nil
} }
func NewHostServer(cnf *utils.ServerConfig) *HostServer { func NewHostServer(task *utils.Tunnel) *HostServer {
s := new(HostServer) s := new(HostServer)
s.config = cnf s.task = task
s.config = utils.DeepCopyConfig(task.Config)
return s return s
} }

View File

@ -15,18 +15,19 @@ type UdpModeServer struct {
udpMap map[string]*utils.Conn udpMap map[string]*utils.Conn
} }
func NewUdpModeServer(bridge *bridge.Tunnel, cnf *utils.ServerConfig) *UdpModeServer { func NewUdpModeServer(bridge *bridge.Bridge, task *utils.Tunnel) *UdpModeServer {
s := new(UdpModeServer) s := new(UdpModeServer)
s.bridge = bridge s.bridge = bridge
s.udpMap = make(map[string]*utils.Conn) s.udpMap = make(map[string]*utils.Conn)
s.config = cnf s.task = task
s.config = utils.DeepCopyConfig(task.Config)
return s return s
} }
//开始 //开始
func (s *UdpModeServer) Start() error { func (s *UdpModeServer) Start() error {
var err error var err error
s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.config.TcpPort, ""}) s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.task.TcpPort, ""})
if err != nil { if err != nil {
return err return err
} }
@ -45,14 +46,14 @@ func (s *UdpModeServer) Start() error {
return nil return nil
} }
//TODO:效率问题有待解决 //TODO:效率问题有待解决--->建立稳定通道,重复利用,提高效率,下个版本
func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) { func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
conn, err := s.bridge.GetTunnel(s.config.ClientId, s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, s.config.Mux) conn, err := s.bridge.GetTunnel(s.task.Client.Id, s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return return
} }
if _, err := conn.WriteHost(utils.CONN_UDP, s.config.Target); err != nil { if _, err := conn.WriteHost(utils.CONN_UDP, s.task.Target); err != nil {
conn.Close() conn.Close()
return return
} }
@ -60,7 +61,7 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
defer func() { defer func() {
if conn != nil && s.config.Mux { if conn != nil && s.config.Mux {
conn.WriteTo([]byte(utils.IO_EOF), s.config.CompressEncode, s.config.Crypt) conn.WriteTo([]byte(utils.IO_EOF), s.config.CompressEncode, s.config.Crypt)
s.bridge.ReturnTunnel(conn, s.config.ClientId) s.bridge.ReturnTunnel(conn, s.task.Client.Id)
} else { } else {
conn.Close() conn.Close()
} }
@ -70,7 +71,6 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
buf := utils.BufPoolUdp.Get().([]byte) buf := utils.BufPoolUdp.Get().([]byte)
out, err := conn.ReadFrom(buf, s.config.CompressDecode, s.config.Crypt) out, err := conn.ReadFrom(buf, s.config.CompressDecode, s.config.Crypt)
if err != nil || err == io.EOF { if err != nil || err == io.EOF {
log.Println("revieve error:", err)
return return
} }
s.listener.WriteToUDP(buf[:out], addr) s.listener.WriteToUDP(buf[:out], addr)

View File

@ -22,7 +22,7 @@ type Flow struct {
} }
type Client struct { type Client struct {
Cnf *ServerConfig Cnf *Config
Id int //id Id int //id
VerifyKey string //验证密钥 VerifyKey string //验证密钥
Addr string //客户端ip地址 Addr string //客户端ip地址
@ -32,35 +32,36 @@ type Client struct {
Flow *Flow Flow *Flow
} }
type ServerConfig struct { type Tunnel struct {
TcpPort int //服务端与客户端通信端口 Id int //Id
VerifyKey string TcpPort int //服务端与客户端通信端口
Mode string //启动方式 Mode string //启动方式
Target string //目标 Target string //目标
Status bool //是否开启
Client *Client //所属客户端id
Flow *Flow
Config *Config
UseClientCnf bool //是否继承客户端配置
Remark string //备注
}
type Config struct {
U string //socks5验证用户名 U string //socks5验证用户名
P string //socks5验证密码 P string //socks5验证密码
Compress string //压缩方式 Compress string //压缩方式
Start int //是否开启
IsRun int //是否在运行
ClientStatus int //客s户端状态
Crypt bool //是否加密 Crypt bool //是否加密
Mux bool //是否加密 Mux bool //是否加密
CompressEncode int //加密方式 CompressEncode int //加密方式
CompressDecode int //解密方式 CompressDecode int //解密方式
Id int //Id
ClientId int //所属客户端id
UseClientCnf bool //是否继承客户端配置
Flow *Flow
Remark string //备注
} }
type HostList struct { type Host struct {
ClientId int //服务端与客户端通信端口
Host string //启动方式 Host string //启动方式
Target string //目标 Target string //目标
HeaderChange string //host修改 HeaderChange string //host修改
HostChange string //host修改 HostChange string //host修改
Flow *Flow Flow *Flow
Client *Client
Remark string //备注 Remark string //备注
} }
@ -70,19 +71,19 @@ func NewCsv() *Csv {
} }
type Csv struct { type Csv struct {
Tasks []*ServerConfig Tasks []*Tunnel
Path string Path string
Hosts []*HostList //域名列表 Hosts []*Host //域名列表
Clients []*Client //客户端 Clients []*Client //客户端
ClientIncreaseId int //客户端id ClientIncreaseId int //客户端id
TaskIncreaseId int //任务自增ID TaskIncreaseId int //任务自增ID
sync.Mutex sync.Mutex
} }
func (s *Csv) Init() { func (s *Csv) Init() {
s.LoadClientFromCsv()
s.LoadTaskFromCsv() s.LoadTaskFromCsv()
s.LoadHostFromCsv() s.LoadHostFromCsv()
s.LoadClientFromCsv()
} }
func (s *Csv) StoreTasksToCsv() { func (s *Csv) StoreTasksToCsv() {
@ -98,16 +99,16 @@ func (s *Csv) StoreTasksToCsv() {
strconv.Itoa(task.TcpPort), strconv.Itoa(task.TcpPort),
task.Mode, task.Mode,
task.Target, task.Target,
task.U, task.Config.U,
task.P, task.Config.P,
task.Compress, task.Config.Compress,
strconv.Itoa(task.Start), utils.GetStrByBool(task.Status),
GetStrByBool(task.Crypt), GetStrByBool(task.Config.Crypt),
GetStrByBool(task.Mux), GetStrByBool(task.Config.Mux),
strconv.Itoa(task.CompressEncode), strconv.Itoa(task.Config.CompressEncode),
strconv.Itoa(task.CompressDecode), strconv.Itoa(task.Config.CompressDecode),
strconv.Itoa(task.Id), strconv.Itoa(task.Id),
strconv.Itoa(task.ClientId), strconv.Itoa(task.Client.Id),
strconv.FormatBool(task.UseClientCnf), strconv.FormatBool(task.UseClientCnf),
task.Remark, task.Remark,
} }
@ -143,27 +144,31 @@ func (s *Csv) LoadTaskFromCsv() {
if err != nil { if err != nil {
log.Fatal("配置文件打开错误:", path) log.Fatal("配置文件打开错误:", path)
} }
var tasks []*ServerConfig var tasks []*Tunnel
// 将每一行数据保存到内存slice中 // 将每一行数据保存到内存slice中
for _, item := range records { for _, item := range records {
post := &ServerConfig{ post := &Tunnel{
TcpPort: GetIntNoErrByStr(item[0]), TcpPort: GetIntNoErrByStr(item[0]),
Mode: item[1], Mode: item[1],
Target: item[2], Target: item[2],
U: item[3], Config: &Config{
P: item[4], U: item[3],
Compress: item[5], P: item[4],
Start: GetIntNoErrByStr(item[6]), Compress: item[5],
Crypt: GetBoolByStr(item[7]), Crypt: GetBoolByStr(item[7]),
Mux: GetBoolByStr(item[8]), Mux: GetBoolByStr(item[8]),
CompressEncode: GetIntNoErrByStr(item[9]), CompressEncode: GetIntNoErrByStr(item[9]),
CompressDecode: GetIntNoErrByStr(item[10]), CompressDecode: GetIntNoErrByStr(item[10]),
Id: GetIntNoErrByStr(item[11]), },
ClientId: GetIntNoErrByStr(item[12]), Status: utils.GetBoolByStr(item[6]),
UseClientCnf: GetBoolByStr(item[13]), Id: GetIntNoErrByStr(item[11]),
Remark: item[14], UseClientCnf: GetBoolByStr(item[13]),
Remark: item[14],
} }
post.Flow = new(Flow) post.Flow = new(Flow)
if post.Client, err = s.GetClient(GetIntNoErrByStr(item[12])); err != nil {
continue
}
tasks = append(tasks, post) tasks = append(tasks, post)
if post.Id > s.TaskIncreaseId { if post.Id > s.TaskIncreaseId {
s.TaskIncreaseId = post.Id s.TaskIncreaseId = post.Id
@ -191,13 +196,13 @@ func (s *Csv) GetIdByVerifyKey(vKey string, addr string) (int, error) {
return 0, errors.New("not found") return 0, errors.New("not found")
} }
func (s *Csv) NewTask(t *ServerConfig) { func (s *Csv) NewTask(t *Tunnel) {
t.Flow = new(Flow) t.Flow = new(Flow)
s.Tasks = append(s.Tasks, t) s.Tasks = append(s.Tasks, t)
s.StoreTasksToCsv() s.StoreTasksToCsv()
} }
func (s *Csv) UpdateTask(t *ServerConfig) error { func (s *Csv) UpdateTask(t *Tunnel) error {
for k, v := range s.Tasks { for k, v := range s.Tasks {
if v.Id == t.Id { if v.Id == t.Id {
s.Tasks = append(s.Tasks[:k], s.Tasks[k+1:]...) s.Tasks = append(s.Tasks[:k], s.Tasks[k+1:]...)
@ -220,7 +225,7 @@ func (s *Csv) DelTask(id int) error {
return errors.New("不存在") return errors.New("不存在")
} }
func (s *Csv) GetTask(id int) (v *ServerConfig, err error) { func (s *Csv) GetTask(id int) (v *Tunnel, err error) {
for _, v = range s.Tasks { for _, v = range s.Tasks {
if v.Id == id { if v.Id == id {
return return
@ -245,7 +250,7 @@ func (s *Csv) StoreHostToCsv() {
record := []string{ record := []string{
host.Host, host.Host,
host.Target, host.Target,
strconv.Itoa(host.ClientId), strconv.Itoa(host.Client.Id),
host.HeaderChange, host.HeaderChange,
host.HostChange, host.HostChange,
host.Remark, host.Remark,
@ -274,7 +279,7 @@ func (s *Csv) LoadClientFromCsv() {
Addr: item[2], Addr: item[2],
Remark: item[3], Remark: item[3],
Status: GetBoolByStr(item[4]), Status: GetBoolByStr(item[4]),
Cnf: &ServerConfig{ Cnf: &Config{
U: item[5], U: item[5],
P: item[6], P: item[6],
Crypt: GetBoolByStr(item[7]), Crypt: GetBoolByStr(item[7]),
@ -297,17 +302,19 @@ func (s *Csv) LoadHostFromCsv() {
if err != nil { if err != nil {
log.Fatal("配置文件打开错误:", path) log.Fatal("配置文件打开错误:", path)
} }
var hosts []*HostList var hosts []*Host
// 将每一行数据保存到内存slice中 // 将每一行数据保存到内存slice中
for _, item := range records { for _, item := range records {
post := &HostList{ post := &Host{
ClientId: GetIntNoErrByStr(item[2]),
Host: item[0], Host: item[0],
Target: item[1], Target: item[1],
HeaderChange: item[3], HeaderChange: item[3],
HostChange: item[4], HostChange: item[4],
Remark: item[5], Remark: item[5],
} }
if post.Client, err = s.GetClient(GetIntNoErrByStr(item[2])); err != nil {
continue
}
post.Flow = new(Flow) post.Flow = new(Flow)
hosts = append(hosts, post) hosts = append(hosts, post)
} }
@ -325,14 +332,14 @@ func (s *Csv) DelHost(host string) error {
return errors.New("不存在") return errors.New("不存在")
} }
func (s *Csv) NewHost(t *HostList) { func (s *Csv) NewHost(t *Host) {
t.Flow = new(Flow) t.Flow = new(Flow)
s.Hosts = append(s.Hosts, t) s.Hosts = append(s.Hosts, t)
s.StoreHostToCsv() s.StoreHostToCsv()
} }
func (s *Csv) UpdateHost(t *HostList) error { func (s *Csv) UpdateHost(t *Host) error {
for k, v := range s.Hosts { for k, v := range s.Hosts {
if v.Host == t.Host { if v.Host == t.Host {
s.Hosts = append(s.Hosts[:k], s.Hosts[k+1:]...) s.Hosts = append(s.Hosts[:k], s.Hosts[k+1:]...)
@ -344,11 +351,11 @@ func (s *Csv) UpdateHost(t *HostList) error {
return errors.New("不存在") return errors.New("不存在")
} }
func (s *Csv) GetHostList(start, length int, id int) ([]*HostList, int) { func (s *Csv) GetHost(start, length int, id int) ([]*Host, int) {
list := make([]*HostList, 0) list := make([]*Host, 0)
var cnt int var cnt int
for _, v := range s.Hosts { for _, v := range s.Hosts {
if id == 0 || v.ClientId == id { if id == 0 || v.Client.Id == id {
cnt++ cnt++
if start--; start < 0 { if start--; start < 0 {
if length--; length > 0 { if length--; length > 0 {
@ -461,27 +468,15 @@ func GetCsvDb() *Csv {
return CsvDb return CsvDb
} }
//深拷贝serverConfig //深拷贝Tunnel
func DeepCopyConfig(c *ServerConfig) *ServerConfig { func DeepCopyConfig(c *Config) *Config {
return &ServerConfig{ return &Config{
TcpPort: c.TcpPort,
VerifyKey: c.VerifyKey,
Mode: c.Mode,
Target: c.Target,
U: c.U, U: c.U,
P: c.P, P: c.P,
Compress: c.Compress, Compress: c.Compress,
Start: c.Start,
IsRun: c.IsRun,
ClientStatus: c.ClientStatus,
Crypt: c.Crypt, Crypt: c.Crypt,
Mux: c.Mux, Mux: c.Mux,
CompressEncode: c.CompressEncode, CompressEncode: c.CompressEncode,
CompressDecode: c.CompressDecode, CompressDecode: c.CompressDecode,
Id: c.Id,
ClientId: c.ClientId,
UseClientCnf: c.UseClientCnf,
Flow: c.Flow,
Remark: c.Remark,
} }
} }

View File

@ -240,6 +240,5 @@ func ReadAllFromFile(filePth string) ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return ioutil.ReadAll(f) return ioutil.ReadAll(f)
} }

View File

@ -33,7 +33,7 @@ func (s *ClientController) Add() {
Id: server.CsvDb.GetClientId(), Id: server.CsvDb.GetClientId(),
Status: true, Status: true,
Remark: s.GetString("Remark"), Remark: s.GetString("Remark"),
Cnf: &utils.ServerConfig{ Cnf: &utils.Config{
U: s.GetString("u"), U: s.GetString("u"),
P: s.GetString("p"), P: s.GetString("p"),
Compress: s.GetString("compress"), Compress: s.GetString("compress"),

View File

@ -57,11 +57,11 @@ func (s *IndexController) All() {
s.display("index/list") s.display("index/list")
} }
func (s *IndexController) GetServerConfig() { func (s *IndexController) GetTunnel() {
start, length := s.GetAjaxParams() start, length := s.GetAjaxParams()
taskType := s.GetString("type") taskType := s.GetString("type")
clientId := s.GetIntNoErr("client_id") clientId := s.GetIntNoErr("client_id")
list, cnt := server.GetServerConfig(start, length, taskType, clientId) list, cnt := server.GetTunnel(start, length, taskType, clientId)
s.AjaxTable(list, cnt, cnt) s.AjaxTable(list, cnt, cnt)
} }
@ -72,22 +72,26 @@ func (s *IndexController) Add() {
s.SetInfo("新增") s.SetInfo("新增")
s.display() s.display()
} else { } else {
t := &utils.ServerConfig{ t := &utils.Tunnel{
TcpPort: s.GetIntNoErr("port"), TcpPort: s.GetIntNoErr("port"),
Mode: s.GetString("type"), Mode: s.GetString("type"),
Target: s.GetString("target"), Target: s.GetString("target"),
U: s.GetString("u"), Config: &utils.Config{
P: s.GetString("p"), U: s.GetString("u"),
Compress: s.GetString("compress"), P: s.GetString("p"),
Crypt: s.GetBoolNoErr("crypt"), Compress: s.GetString("compress"),
Mux: s.GetBoolNoErr("mux"), Crypt: s.GetBoolNoErr("crypt"),
IsRun: 0, Mux: s.GetBoolNoErr("mux"),
},
Id: server.CsvDb.GetTaskId(), Id: server.CsvDb.GetTaskId(),
ClientId: s.GetIntNoErr("client_id"),
UseClientCnf: s.GetBoolNoErr("use_client"), UseClientCnf: s.GetBoolNoErr("use_client"),
Start: 1, Status: true,
Remark: s.GetString("remark"), Remark: s.GetString("remark"),
} }
var err error
if t.Client, err = server.CsvDb.GetClient(s.GetIntNoErr("client_id")); err != nil {
s.AjaxErr(err.Error())
}
server.CsvDb.NewTask(t) server.CsvDb.NewTask(t)
if err := server.AddTask(t); err != nil { if err := server.AddTask(t); err != nil {
s.AjaxErr(err.Error()) s.AjaxErr(err.Error())
@ -115,12 +119,12 @@ func (s *IndexController) Edit() {
t.Mode = s.GetString("type") t.Mode = s.GetString("type")
t.Target = s.GetString("target") t.Target = s.GetString("target")
t.Id = id t.Id = id
t.ClientId = s.GetIntNoErr("client_id") t.Client.Id = s.GetIntNoErr("client_id")
t.U = s.GetString("u") t.Config.U = s.GetString("u")
t.P = s.GetString("p") t.Config.P = s.GetString("p")
t.Compress = s.GetString("compress") t.Config.Compress = s.GetString("compress")
t.Crypt = s.GetBoolNoErr("crypt") t.Config.Crypt = s.GetBoolNoErr("crypt")
t.Mux = s.GetBoolNoErr("mux") t.Config.Mux = s.GetBoolNoErr("mux")
t.UseClientCnf = s.GetBoolNoErr("use_client") t.UseClientCnf = s.GetBoolNoErr("use_client")
t.Remark = s.GetString("remark") t.Remark = s.GetString("remark")
server.CsvDb.UpdateTask(t) server.CsvDb.UpdateTask(t)
@ -162,7 +166,7 @@ func (s *IndexController) HostList() {
} else { } else {
start, length := s.GetAjaxParams() start, length := s.GetAjaxParams()
clientId := s.GetIntNoErr("client_id") clientId := s.GetIntNoErr("client_id")
list, cnt := server.CsvDb.GetHostList(start, length, clientId) list, cnt := server.CsvDb.GetHost(start, length, clientId)
s.AjaxTable(list, cnt, cnt) s.AjaxTable(list, cnt, cnt)
} }
} }
@ -182,8 +186,10 @@ func (s *IndexController) AddHost() {
s.SetInfo("新增") s.SetInfo("新增")
s.display("index/hadd") s.display("index/hadd")
} else { } else {
h := &utils.HostList{ h := &utils.Host{
ClientId: s.GetIntNoErr("client_id"), Client: &utils.Client{
Id: s.GetIntNoErr("client_id"),
},
Host: s.GetString("host"), Host: s.GetString("host"),
Target: s.GetString("target"), Target: s.GetString("target"),
HeaderChange: s.GetString("header"), HeaderChange: s.GetString("header"),
@ -199,7 +205,7 @@ func (s *IndexController) EditHost() {
host := s.GetString("host") host := s.GetString("host")
if s.Ctx.Request.Method == "GET" { if s.Ctx.Request.Method == "GET" {
s.Data["menu"] = "host" s.Data["menu"] = "host"
if h, _, err := server.GetKeyByHost(host); err != nil { if h, err := server.GetInfoByHost(host); err != nil {
s.error() s.error()
} else { } else {
s.Data["h"] = h s.Data["h"] = h
@ -207,10 +213,10 @@ func (s *IndexController) EditHost() {
s.SetInfo("修改") s.SetInfo("修改")
s.display("index/hedit") s.display("index/hedit")
} else { } else {
if h, _, err := server.GetKeyByHost(host); err != nil { if h, err := server.GetInfoByHost(host); err != nil {
s.error() s.error()
} else { } else {
h.ClientId = s.GetIntNoErr("client_id") h.Client.Id = s.GetIntNoErr("client_id")
h.Host = s.GetString("nhost") h.Host = s.GetString("nhost")
h.Target = s.GetString("target") h.Target = s.GetString("target")
h.HeaderChange = s.GetString("header") h.HeaderChange = s.GetString("header")

View File

@ -31,7 +31,7 @@
</div> </div>
<div class="form-group" id="client_id"> <div class="form-group" id="client_id">
<label class="control-label">ID</label> <label class="control-label">ID</label>
<input class="form-control" value="{{.t.ClientId}}" type="text" name="client_id" <input class="form-control" value="{{.t.Client.Id}}" type="text" name="client_id"
placeholder="客户端id"> placeholder="客户端id">
</div> </div>
<div class="form-group" id="use_client"> <div class="form-group" id="use_client">
@ -44,32 +44,32 @@
<div class="form-group" id="compress"> <div class="form-group" id="compress">
<label class="control-label">()</label> <label class="control-label">()</label>
<select class="form-control" name="compress"> <select class="form-control" name="compress">
<option {{if eq "" .t.Compress}}selected{{end}} value=""></option> <option {{if eq "" .t.Config.Compress}}selected{{end}} value=""></option>
<option {{if eq "snappy" .t.Compress}}selected{{end}} value="snappy">snappy</option> <option {{if eq "snappy" .t.Config.Compress}}selected{{end}} value="snappy">snappy</option>
</select> </select>
</div> </div>
<div class="form-group" id="crypt"> <div class="form-group" id="crypt">
<label class="control-label">()</label> <label class="control-label">()</label>
<select class="form-control" name="crypt"> <select class="form-control" name="crypt">
<option {{if eq false .t.Crypt}}selected{{end}} value="0"></option> <option {{if eq false .t.Config.Crypt}}selected{{end}} value="0"></option>
<option {{if eq true .t.Crypt}}selected{{end}} value="1"></option> <option {{if eq true .t.Config.Crypt}}selected{{end}} value="1"></option>
</select> </select>
</div> </div>
<div class="form-group" id="mux"> <div class="form-group" id="mux">
<label class="control-label">TCP()</label> <label class="control-label">TCP()</label>
<select class="form-control" name="mux"> <select class="form-control" name="mux">
<option {{if eq false .t.Mux}}selected{{end}} value="0"></option> <option {{if eq false .t.Config.Mux}}selected{{end}} value="0"></option>
<option {{if eq true .t.Mux}}selected{{end}} value="1"></option> <option {{if eq true .t.Config.Mux}}selected{{end}} value="1"></option>
</select> </select>
</div> </div>
<div class="form-group" id="u"> <div class="form-group" id="u">
<label class="control-label">(socks5,web穿)</label> <label class="control-label">(socks5,web穿)</label>
<input class="form-control" value="{{.t.U}}" type="text" name="u" <input class="form-control" value="{{.t.Config.U}}" type="text" name="u"
placeholder="不填则无需验证"> placeholder="不填则无需验证">
</div> </div>
<div class="form-group" id="p"> <div class="form-group" id="p">
<label class="control-label">(socks5,web穿)</label> <label class="control-label">(socks5,web穿)</label>
<input class="form-control" value="{{.t.P}}" type="text" name="p" <input class="form-control" value="{{.t.Config.P}}" type="text" name="p"
placeholder="不填则无需验证"> placeholder="不填则无需验证">
</div> </div>
</form> </form>

View File

@ -15,7 +15,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label">id</label> <label class="control-label">id</label>
<input class="form-control" value="{{.h.ClientId}}" type="text" name="client_id" <input class="form-control" value="{{.h.Client.Id}}" type="text" name="client_id"
placeholder="客户端id"> placeholder="客户端id">
</div> </div>
<div class="form-group"> <div class="form-group">

View File

@ -10,6 +10,11 @@
<th>host</th> <th>host</th>
<th></th> <th></th>
<th>host</th> <th>host</th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th> <th></th>
<th></th> <th></th>
<th></th> <th></th>
@ -68,13 +73,18 @@
}, },
dom: '<"top"fl><"toolbar">rt<"bottom"ip><"clear">', dom: '<"top"fl><"toolbar">rt<"bottom"ip><"clear">',
columns: [ //这个是显示到界面上的个数据 格式为 {data:'显示的字段名'} columns: [ //这个是显示到界面上的个数据 格式为 {data:'显示的字段名'}
{data: 'ClientId'}, {data: 'Remark'},
{data: 'Remark'}, {data: 'Remark'},
{data: 'Host'}, {data: 'Host'},
{data: 'Target'}, {data: 'Target'},
{data: 'HostChange'}, {data: 'HostChange'},
{data: 'HostChange'}, {data: 'HostChange'},
{data: 'HostChange'}, {data: 'HostChange'},
{data: 'HostChange'},
{data: 'HostChange'},
{data: 'HostChange'},
{data: 'HostChange'},
{data: 'HostChange'},
{data: 'Target'}, {data: 'Target'},
], ],
bFilter: false, bFilter: false,
@ -88,6 +98,12 @@
+ ' </div>' + ' </div>'
} }
}, },
{
targets: 1,
render: function (data, type, row, meta) {
return row.Client.Id
}
},
{ {
targets: -2, targets: -2,
render: function (data, type, row, meta) { render: function (data, type, row, meta) {
@ -99,6 +115,46 @@
render: function (data, type, row, meta) { render: function (data, type, row, meta) {
return change(row.Flow.ExportFlow) return change(row.Flow.ExportFlow)
} }
},
{
targets: -4,
render: function (data, type, row, meta) {
return row.Client.Cnf.P
}
},
{
targets: -5,
render: function (data, type, row, meta) {
return row.Client.Cnf.U
}
},
{
targets: -6,
render: function (data, type, row, meta) {
if (row.Client.Cnf.Mux == "0") {
return "不启用"
} else {
return "启用"
}
}
}
,
{
targets: -7,
render: function (data, type, row, meta) {
if (row.Client.Cnf.Crypt == "0") {
return "不加密"
} else {
return "加密"
}
}
}
,
{
targets: -8,
render: function (data, type, row, meta) {
return row.Client.Cnf.Compress
}
} }
], ],
buttons: [] buttons: []

View File

@ -102,7 +102,7 @@
autoWidth: false, autoWidth: false,
ordering: false, ordering: false,
ajax: { ajax: {
url: '/index/getserverconfig?type={{.type}}' + "&client_id=" +{{.client_id}}, url: '/index/gettunnel?type={{.type}}' + "&client_id=" +{{.client_id}},
type: 'POST' type: 'POST'
}, },
dom: '<"top"fl><"toolbar">rt<"bottom"ip><"clear">', dom: '<"top"fl><"toolbar">rt<"bottom"ip><"clear">',
@ -118,7 +118,7 @@
{data: 'U'}, {data: 'U'},
{data: 'P'}, {data: 'P'},
{data: 'ClientStatus'}, {data: 'ClientStatus'},
{data: 'IsRun'}, {data: 'Status'},
{data: 'ExportFlow'}, {data: 'ExportFlow'},
{data: 'InletFlow'}, {data: 'InletFlow'},
{data: "Id"} {data: "Id"}
@ -127,7 +127,7 @@
columnDefs: [{ columnDefs: [{
targets: -1, targets: -1,
render: function (data, type, row, meta) { render: function (data, type, row, meta) {
if (row.IsRun == 1) { if (row.Status == 1) {
btn = "<button onclick=\"stop('" + row.Id + "')\" class=\"btn btn-secondary btn-sm\" type=\"button\">关闭</button>" btn = "<button onclick=\"stop('" + row.Id + "')\" class=\"btn btn-secondary btn-sm\" type=\"button\">关闭</button>"
} else { } else {
btn = "<button onclick=\"start('" + row.Id + "')\" class=\"btn btn-success btn-sm\" type=\"button\">打开</button>" btn = "<button onclick=\"start('" + row.Id + "')\" class=\"btn btn-success btn-sm\" type=\"button\">打开</button>"
@ -137,11 +137,43 @@
'<button onclick="del(\'' + row.Id + '\')" type="button" class="btn btn-danger btn-sm"></button>' + '<button onclick="del(\'' + row.Id + '\')" type="button" class="btn btn-danger btn-sm"></button>' +
btn_edit + btn + ' </div>' btn_edit + btn + ' </div>'
} }
}, {
targets: 2,
render: function (data, type, row, meta) {
return row.Client.Id
}
}, {
targets: 5,
render: function (data, type, row, meta) {
if (row.UseClientCnf == true) {
return row.Client.Cnf.Compress
} else {
return row.Config.Compress
}
}
}, {
targets: 8,
render: function (data, type, row, meta) {
if (row.UseClientCnf == true) {
return row.Client.Cnf.U
} else {
return row.Config.U
}
}
}, {
targets: 9,
render: function (data, type, row, meta) {
if (row.UseClientCnf == true) {
return row.Client.Cnf.P
} else {
return row.Config.P
}
}
}, },
{ {
targets: -4, targets: -4,
render: function (data, type, row, meta) { render: function (data, type, row, meta) {
if (data == 0) { if (data == false) {
return "<span class=\"badge badge-pill badge-secondary\">暂停</span>" return "<span class=\"badge badge-pill badge-secondary\">暂停</span>"
} else { } else {
return "<span class=\"badge badge-pill badge-success\">正常</span>" return "<span class=\"badge badge-pill badge-success\">正常</span>"
@ -151,7 +183,12 @@
{ {
targets: -9, targets: -9,
render: function (data, type, row, meta) { render: function (data, type, row, meta) {
if (data == "0") { if (row.UseClientCnf == true) {
crypt = row.Client.Cnf.Crypt
} else {
crypt = row.Config.Crypt
}
if (crypt == "0") {
return "不加密" return "不加密"
} else { } else {
return "加密" return "加密"
@ -161,7 +198,12 @@
{ {
targets: -8, targets: -8,
render: function (data, type, row, meta) { render: function (data, type, row, meta) {
if (data == "0") { if (row.UseClientCnf == true) {
mux = row.Client.Cnf.Mux
} else {
mux = row.Config.Mux
}
if (mux == "0") {
return "不启用" return "不启用"
} else { } else {
return "启用" return "启用"
@ -171,7 +213,7 @@
{ {
targets: -5, targets: -5,
render: function (data, type, row, meta) { render: function (data, type, row, meta) {
if (data == 0) { if (row.Client.IsConnect == false) {
return "<span class=\"badge badge-pill badge-secondary\">离线</span>" return "<span class=\"badge badge-pill badge-secondary\">离线</span>"
} else { } else {
return "<span class=\"badge badge-pill badge-success\">在线</span>" return "<span class=\"badge badge-pill badge-success\">在线</span>"