diff --git a/README.md b/README.md index 0c65676..3c23219 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # easyProxy    -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等等,但要使用第三方的公网服务器就必须为第三方付费,并且这些服务都有各种各样的限制,此外,由于数据包会流经第三方,因此对数据安全也是一大隐患。 @@ -38,33 +38,47 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透** - [x] 支持一个服务端,多个客户端模式 - [x] host修改支持 - [x] 自定义设置header支持 +- [x] 流量统计 +- [x] 自动义404页面 +- [x] 热更新支持 ## 目录 -1. [安装](#安装) -2. [web管理模式](#web管理模式)(多隧道时推荐) -3. [tcp隧道模式](#tcp隧道模式) -4. [udp隧道模式](#udp隧道模式) -5. [socks5代理模式](#socks5代理模式) -6. [http代理模式](#http代理模式) -7. [数据压缩支持](#数据压缩支持) -8. [站点密码保护](#站点保护) -9. [加密传输](#加密传输) -10. [TCP多路复用](#多路复用) -11. [host修改](#host修改) -12. [自定义header](#自定义header) -13. [获取用户真实ip](#获取用户真实ip) +* [安装](#安装) + * [编译安装](#源码安装) + * [release安装](#release安装) +* [web管理](#web管理模式)(多隧道时推荐) + * [启动](#启动) + * [配置文件说明](#服务端配置文件) +* 单隧道模式及介绍 + * [tcp隧道模式](#tcp隧道模式) + * [udp隧道模式](#udp隧道模式) + * [socks5代理模式](#socks5代理模式) + * [http代理模式](#http代理模式) +* [相关功能](#相关功能) + * [数据压缩支持](#数据压缩支持) + * [站点密码保护](#站点保护) + * [加密传输](#加密传输) + * [TCP多路复用](#多路复用) + * [host修改](#host修改) + * [自定义header](#自定义header) + * [获取用户真实ip](#获取用户真实ip) + * [热更新支持](#热更新支持) + * [客户端地址显示](#客户端地址显示) + * [自定义404页面](#404页面配置) + * [流量统计](#流量统计) + * [连接池](#连接池) ## 安装 -1. release安装 +### release安装 > https://github.com/cnlh/easyProxy/releases 下载对应的系统版本即可,服务端和客户端是单独的,go语言开发,无需任何第三方依赖 -2. 源码安装 -- 安装源码 +### 源码安装 +- 安装源码(另有snappy、beego包) > go get github.com/cnlh/easyProxy - 编译 > go build cmd/server/proxy_server.go @@ -89,35 +103,7 @@ tcpport | 服务端客户端通信端口 **提示:使用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 ``` -名称 | 含义 ----|--- -mode | 运行模式 + - 客户端 +``` + ./proxy_server -server=ip:port -vkey=web界面中显示的 +``` 进入web管理界面,有详细的命令 @@ -316,30 +303,31 @@ httpport | http代理连接端口 配置HTTP代理即可,ip为外网服务器ip,端口为httpport,即可在外网环境访问内网啦! ``` -## 数据压缩支持 +## 相关功能 + +### 数据压缩支持 由于是内网穿透,内网客户端与服务端之间的隧道存在大量的数据交换,为节省流量,加快传输速度,由此本程序支持SNNAPY形式的压缩。 - 所有模式均支持数据压缩,可以与加密同时使用 - - +- 开启此功能会增加cpu和内存消耗 - 在server端加上参数 -compress=snappy(或在web管理中设置) ``` -compress=snappy ``` -## 加密传输 +### 加密传输 如果公司内网防火墙对外网访问进行了流量识别与屏蔽,例如禁止了ssh协议等,通过设置 配置文件,将服务端与客户端之间的通信内容加密传输,将会有效防止流量被拦截。 - +- 开启此功能会增加cpu和内存消耗 - 在server端加上参数 -crypt=true(或在web管理中设置) ``` -crypt=true ``` -## 多路复用 +### 多路复用 客户端和服务器端之间的连接支持多路复用,不再需要为每一个用户请求创建一个连接,使连接建立的延迟降低,并且避免了大量文件描述符的占用。 @@ -351,7 +339,7 @@ httpport | http代理连接端口 ``` -## 站点保护 +### 站点保护 由于所有客户端共用一个 http 服务端口,任何知道你的域名和 url 的人都能访问到你部署在内网的 web 服务,但是在某些场景下需要确保只有限定的用户才能访问。 easyProxy支持通过 HTTP Basic Auth 来保护你的 web 服务,使用户需要通过用户名和密码才能访问到你的服务。 @@ -361,25 +349,37 @@ easyProxy支持通过 HTTP Basic Auth 来保护你的 web 服务,使用户需 -u=user -p=password ``` -web管理中也可配置 +- web管理中也可配置 -## host修改 +### host修改 通常情况下本代理不会修改转发的任何数据。但有一些后端服务会根据 http 请求 header 中的 host 字段来展现不同的网站,例如 nginx 的虚拟主机服务,启用 host-header 的修改功能可以动态修改 http 请求中的 host 字段。该功能仅限于域名代理模式。 **使用方法:在web管理中设置** -## 自定义header +### 自定义header 支持对header进行新增或者修改,以配合服务的需要 -## 获取用户真实ip +### 获取用户真实ip 目前只有域名模式的代理支持这一功能,可以通过用户请求的 header 中的 X-Forwarded-For 和 X-Real-IP 来获取用户真实 IP。 **本代理前会在每一个请求中添加了这两个 header。** +### 热更新支持 +在web管理中的修改将实时使用,无需重启客户端或者服务端 + +### 客户端地址显示 +在web管理中将显示客户端的连接地址 + +### 404页面配置 +支持域名解析模式的自定义404页面,修改/web/static/page/error.html中内容即可,暂不支持静态文件等内容 + +### 流量统计 +可统计显示每个代理使用的流量,由于压缩和加密等原因,会和实际环境中的略有差异 + +### 连接池 + easyProxy会预先和后端服务建立起指定数量的连接,每次接收到用户请求后,会从连接池中取出一个连接和用户连接关联起来,避免了等待与后端服务建立连接时间。 -## 操作系统支持 -支持Windows、Linux、MacOSX等,无第三方依赖库。 diff --git a/bridge/bridge.go b/bridge/bridge.go index 06a9b6c..8c6fa46 100755 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -31,7 +31,7 @@ func newList() *list { return l } -type Tunnel struct { +type Bridge struct { TunnelPort int //通信隧道端口 listener *net.TCPListener //server端监听 SignalList map[int]*list //通信 @@ -41,8 +41,8 @@ type Tunnel struct { tunnelLock sync.Mutex } -func NewTunnel(tunnelPort int, runList map[int]interface{}) *Tunnel { - t := new(Tunnel) +func NewTunnel(tunnelPort int, runList map[int]interface{}) *Bridge { + t := new(Bridge) t.TunnelPort = tunnelPort t.SignalList = 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 } -func (s *Tunnel) StartTunnel() error { +func (s *Bridge) StartTunnel() error { var err error s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.TunnelPort, ""}) if err != nil { @@ -61,7 +61,7 @@ func (s *Tunnel) StartTunnel() error { } //tcp server -func (s *Tunnel) tunnelProcess() error { +func (s *Bridge) tunnelProcess() error { var err error for { conn, err := s.listener.Accept() @@ -75,12 +75,12 @@ func (s *Tunnel) tunnelProcess() error { } //验证失败,返回错误验证flag,并且关闭连接 -func (s *Tunnel) verifyError(c *utils.Conn) { +func (s *Bridge) verifyError(c *utils.Conn) { c.Conn.Write([]byte(utils.VERIFY_EER)) 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)) vval := make([]byte, 32) if _, err := c.Conn.Read(vval); err != nil { @@ -104,7 +104,7 @@ func (s *Tunnel) cliProcess(c *utils.Conn) error { } //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 { case utils.WORK_MAIN: log.Println("客户端连接成功", c.Conn.RemoteAddr()) @@ -119,7 +119,7 @@ func (s *Tunnel) typeDeal(typeVal string, c *utils.Conn, id int) error { } //加到对应的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() if v, ok := m[id]; ok { 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 err error retry: @@ -148,7 +148,7 @@ retry: //得到一个tcp隧道 //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: if c, err = s.waitAndPop(s.TunnelList, id); err != nil { 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 { err = errors.New("客户端未连接") return @@ -172,14 +172,14 @@ func (s *Tunnel) GetSignal(id int) (err error, conn *utils.Conn) { } //重回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 { v.Add(conn) } } //重回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 { utils.FlushConn(conn.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) } //删除隧道 -func (s *Tunnel) DelClientTunnel(id int) { +func (s *Bridge) DelClientTunnel(id int) { 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 { for { 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) stop := time.After(time.Second * 3) for { @@ -231,7 +231,7 @@ func (s *Tunnel) waitAndPop(m map[int]*list, id int) (c *utils.Conn, err error) return } -func (s *Tunnel) verify(id int) bool { +func (s *Bridge) verify(id int) bool { for k := range s.RunList { if k == id { return true diff --git a/cmd/proxy_server/proxy_server.go b/cmd/proxy_server/proxy_server.go index 23bfb34..74d055b 100644 --- a/cmd/proxy_server/proxy_server.go +++ b/cmd/proxy_server/proxy_server.go @@ -24,22 +24,32 @@ var ( func main() { flag.Parse() - server.VerifyKey = *VerifyKey - cnf := &utils.ServerConfig{ - TcpPort: *httpPort, - Mode: *rpMode, - Target: *tunnelTarget, - VerifyKey: *VerifyKey, - U: *u, - P: *p, - Compress: *compress, - Start: 0, - IsRun: 0, - ClientStatus: 0, - Crypt: utils.GetBoolByStr(*crypt), - Mux: utils.GetBoolByStr(*mux), - CompressEncode: 0, - CompressDecode: 0, + task := &utils.Tunnel{ + TcpPort: *httpPort, + Mode: *rpMode, + Target: *tunnelTarget, + Config: &utils.Config{ + U: *u, + P: *p, + Compress: *compress, + Crypt: utils.GetBoolByStr(*crypt), + Mux: utils.GetBoolByStr(*mux), + }, + Flow: &utils.Flow{}, + UseClientCnf: false, + } + if *VerifyKey != "" { + 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 { p, err := beego.AppConfig.Int("tcpport") @@ -50,6 +60,6 @@ func main() { } } log.Println("服务端启动,监听tcp服务端端口:", *TcpPort) - cnf.CompressDecode, cnf.CompressEncode = utils.GetCompressType(cnf.Compress) - server.StartNewServer(*TcpPort, cnf) + task.Config.CompressDecode, task.Config.CompressEncode = utils.GetCompressType(task.Config.Compress) + server.StartNewServer(*TcpPort, task) } diff --git a/conf/clients.csv b/conf/clients.csv index 206dcd6..5e3eeda 100644 --- a/conf/clients.csv +++ b/conf/clients.csv @@ -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 +2,zl4p3da659qa9rh3,127.0.0.1:52096,测试2,true,1,1,1,1,snappy diff --git a/conf/hosts.csv b/conf/hosts.csv index b4ba649..949dbc6 100644 --- a/conf/hosts.csv +++ b/conf/hosts.csv @@ -1,2 +1,2 @@ -a.o.com,127.0.0.1:8080,1,,,测试2 b.o.com,127.0.0.1:8082,2,,,测试 +a.o.com,127.0.0.1:8080,1,Connection: close,,测试2 diff --git a/conf/tasks.csv b/conf/tasks.csv index 4043561..442bf46 100644 --- a/conf/tasks.csv +++ b/conf/tasks.csv @@ -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,0,2,2,true,udp测试 -8024,socks5Server,,,,,1,0,0,0,0,3,2,true,socks5测试 -8025,httpProxyServer,,,,,1,0,0,0,0,4,2,true,http测试 +53,udpServer,114.114.114.114:53,,,,1,0,0,0,1,2,2,true,udp测试 +9001,tunnelServer,127.0.0.1:8080,1,1,snappy,1,1,1,0,0,1,1,false,test +9009,tunnelServer,127.0.0.1:5900,,,,1,0,0,0,0,5,2,true,vnc +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测试 diff --git a/image/web.png b/image/web.png index c96aea8..ee59c81 100644 Binary files a/image/web.png and b/image/web.png differ diff --git a/image/web2.png b/image/web2.png index 63967d6..2b97c9c 100644 Binary files a/image/web2.png and b/image/web2.png differ diff --git a/server/base.go b/server/base.go index 74f1daf..90ab34a 100644 --- a/server/base.go +++ b/server/base.go @@ -8,53 +8,47 @@ import ( //server base struct type server struct { - bridge *bridge.Tunnel - config *utils.ServerConfig + bridge *bridge.Bridge + task *utils.Tunnel + config *utils.Config sync.Mutex } -func (s *server) GetTunnelAndWriteHost(connType string, cnf *utils.ServerConfig, addr string) (*utils.Conn, error) { - var err error - link, err := s.bridge.GetTunnel(cnf.ClientId, cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, cnf.Mux) - if err != nil { - return nil, err +func (s *server) GetTunnelAndWriteHost(connType string, clientId int, cnf *utils.Config, addr string) (link *utils.Conn, err error) { + if link, err = s.bridge.GetTunnel(clientId, cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, cnf.Mux); err != nil { + return } if _, err = link.WriteHost(connType, addr); err != nil { link.Close() - return nil, err } - return link, nil + return } func (s *server) FlowAdd(in, out int64) { s.Lock() defer s.Unlock() - if s.config.Flow == nil { - s.config.Flow = new(utils.Flow) - } - s.config.Flow.ExportFlow += out - s.config.Flow.InletFlow += in + s.task.Flow.ExportFlow += out + s.task.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() defer s.Unlock() - if s.config.Flow == nil { - s.config.Flow = new(utils.Flow) - } host.Flow.ExportFlow += out host.Flow.InletFlow += in } //热更新配置 func (s *server) ResetConfig() { - task, err := CsvDb.GetTask(s.config.Id) + //获取最新数据 + task, err := CsvDb.GetTask(s.task.Id) if err != nil { return } - s.config.UseClientCnf = task.UseClientCnf - if s.config.UseClientCnf { - client, err := CsvDb.GetClient(s.config.ClientId) + s.task.UseClientCnf = task.UseClientCnf + //使用客户端配置 + if s.task.UseClientCnf { + client, err := CsvDb.GetClient(s.task.Client.Id) if err == nil { s.config.U = client.Cnf.U s.config.P = client.Cnf.P @@ -62,15 +56,14 @@ func (s *server) ResetConfig() { s.config.Mux = client.Cnf.Mux s.config.Crypt = client.Cnf.Crypt } - s.config.CompressDecode, s.config.CompressEncode = utils.GetCompressType(client.Cnf.Compress) } else { if err == nil { - s.config.U = task.U - s.config.P = task.P - s.config.Compress = task.Compress - s.config.Mux = task.Mux - s.config.Crypt = task.Crypt + s.config.U = task.Config.U + s.config.P = task.Config.P + s.config.Compress = task.Config.Compress + s.config.Mux = task.Config.Mux + 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) } diff --git a/server/process.go b/server/process.go index f564bfd..341a3a0 100644 --- a/server/process.go +++ b/server/process.go @@ -13,13 +13,7 @@ type process func(c *utils.Conn, s *TunnelModeServer) error //tcp隧道模式 func ProcessTunnel(c *utils.Conn, s *TunnelModeServer) error { - _, _, rb, err, r := c.GetHost() - 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) + return s.dealClient(c, s.config, s.task.Target, "", nil) } //http代理模式 @@ -41,8 +35,7 @@ func ProcessHost(c *utils.Conn, s *TunnelModeServer) error { var ( isConn = true link *utils.Conn - client *utils.Client - host *utils.HostList + host *utils.Host wg sync.WaitGroup ) for { @@ -52,17 +45,17 @@ func ProcessHost(c *utils.Conn, s *TunnelModeServer) error { } //首次获取conn 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) break } - client.Cnf.ClientId = host.ClientId - 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 { + host.Client.Cnf.CompressDecode, host.Client.Cnf.CompressEncode = utils.GetCompressType(host.Client.Cnf.Compress) + + if err = s.auth(r, c, host.Client.Cnf.U, host.Client.Cnf.P); err != nil { 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) break } @@ -72,27 +65,28 @@ func ProcessHost(c *utils.Conn, s *TunnelModeServer) error { } else { wg.Add(1) 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() s.FlowAddHost(host, 0, out) }() } isConn = false } + //根据设定,修改header和host utils.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String()) b, err := httputil.DumpRequest(r, true) - s.FlowAddHost(host, int64(len(b)), 0) if err != nil { 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 } } wg.Wait() - if client != nil && client.Cnf != nil && client.Cnf.Mux && link != nil { - link.WriteTo([]byte(utils.IO_EOF), client.Cnf.CompressEncode, client.Cnf.Crypt) - s.bridge.ReturnTunnel(link, client.Id) + if host != nil && host.Client.Cnf != nil && host.Client.Cnf.Mux && link != nil { + link.WriteTo([]byte(utils.IO_EOF), host.Client.Cnf.CompressEncode, host.Client.Cnf.Crypt) + s.bridge.ReturnTunnel(link, host.Client.Id) } else if link != nil { link.Close() } @@ -103,5 +97,3 @@ func ProcessHost(c *utils.Conn, s *TunnelModeServer) error { c.Close() return nil } - - diff --git a/server/server.go b/server/server.go index 06dfe51..c9808ca 100644 --- a/server/server.go +++ b/server/server.go @@ -20,10 +20,9 @@ type RunServer struct { } var ( - Bridge *bridge.Tunnel + Bridge *bridge.Bridge RunList map[int]interface{} //运行中的任务 CsvDb = utils.GetCsvDb() - VerifyKey string ) func init() { @@ -33,7 +32,7 @@ func init() { //从csv文件中恢复任务 func InitFromCsv() { for _, v := range CsvDb.Tasks { - if v.Start == 1 { + if v.Status { log.Println("启动模式:", v.Mode, "监听端口:", v.TcpPort) AddTask(v) } @@ -41,7 +40,7 @@ func InitFromCsv() { } //start a new server -func StartNewServer(bridgePort int, cnf *utils.ServerConfig) { +func StartNewServer(bridgePort int, cnf *utils.Tunnel) { Bridge = bridge.NewTunnel(bridgePort, RunList) if err := Bridge.StartTunnel(); err != nil { log.Fatalln("服务端开启失败", err) @@ -58,37 +57,32 @@ func StartNewServer(bridgePort int, cnf *utils.ServerConfig) { } //new a server by mode name -func NewMode(Bridge *bridge.Tunnel, c *utils.ServerConfig) interface{} { - config := utils.DeepCopyConfig(c) - switch config.Mode { +func NewMode(Bridge *bridge.Bridge, c *utils.Tunnel) interface{} { + switch c.Mode { case "tunnelServer": - return NewTunnelModeServer(ProcessTunnel, Bridge, config) + return NewTunnelModeServer(ProcessTunnel, Bridge, c) case "socks5Server": - return NewSock5ModeServer(Bridge, config) + return NewSock5ModeServer(Bridge, c) case "httpProxyServer": - return NewTunnelModeServer(ProcessHttp, Bridge, config) + return NewTunnelModeServer(ProcessHttp, Bridge, c) case "udpServer": - return NewUdpModeServer(Bridge, config) + return NewUdpModeServer(Bridge, c) case "webServer": InitFromCsv() p, _ := beego.AppConfig.Int("hostPort") - t := &utils.ServerConfig{ - TcpPort: p, - Mode: "httpHostServer", - Target: "", - U: "", - P: "", - Compress: "", - Start: 1, - IsRun: 0, - ClientStatus: 0, + t := &utils.Tunnel{ + TcpPort: p, + Mode: "httpHostServer", + Target: "", + Config: &utils.Config{}, + Status: true, } AddTask(t) return NewWebServer(Bridge) case "hostServer": - return NewHostServer(config) + return NewHostServer(c) case "httpHostServer": - return NewTunnelModeServer(ProcessHost, Bridge, config) + return NewTunnelModeServer(ProcessHost, Bridge, c) } return nil } @@ -100,7 +94,7 @@ func StopServer(id int) error { if t, err := CsvDb.GetTask(id); err != nil { return err } else { - t.Start = 0 + t.Status = false CsvDb.UpdateTask(t) } return nil @@ -109,7 +103,7 @@ func StopServer(id int) error { } //add task -func AddTask(t *utils.ServerConfig) error { +func AddTask(t *utils.Tunnel) error { if svr := NewMode(Bridge, t); svr != nil { RunList[t.Id] = svr go func() { @@ -131,7 +125,7 @@ func StartTask(id int) error { return err } else { AddTask(t) - t.Start = 1 + t.Status = true CsvDb.UpdateTask(t) } return nil @@ -146,12 +140,11 @@ func DelTask(id int) error { } //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 { s := strings.Split(host, ":") if s[0] == v.Host { h = v - t, err = CsvDb.GetClient(v.ClientId) return } } @@ -160,39 +153,25 @@ func GetKeyByHost(host string) (h *utils.HostList, t *utils.Client, err error) { } //get task list by page num -func GetServerConfig(start, length int, typeVal string, clientId int) ([]*utils.ServerConfig, int) { - list := make([]*utils.ServerConfig, 0) +func GetTunnel(start, length int, typeVal string, clientId int) ([]*utils.Tunnel, int) { + list := make([]*utils.Tunnel, 0) var cnt int 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 } - 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++ + if _, ok := Bridge.SignalList[v.Client.Id]; ok { + v.Client.IsConnect = true + } else { + v.Client.IsConnect = false + } if start--; start < 0 { if length--; length > 0 { if _, ok := RunList[v.Id]; ok { - v.IsRun = 1 + v.Client.Status = true } else { - v.IsRun = 0 - } - if s, ok := Bridge.SignalList[v.ClientId]; ok { - if s.Len() > 0 { - v.ClientStatus = 1 - } else { - v.ClientStatus = 0 - } - } else { - v.ClientStatus = 0 + v.Client.Status = false } list = append(list, v) } @@ -218,13 +197,13 @@ func dealClientData(list []*utils.Client) { v.Flow.InletFlow = 0 v.Flow.ExportFlow = 0 for _, h := range CsvDb.Hosts { - if h.ClientId == v.Id { + if h.Client.Id == v.Id { v.Flow.InletFlow += h.Flow.InletFlow v.Flow.ExportFlow += h.Flow.ExportFlow } } for _, t := range CsvDb.Tasks { - if t.ClientId == v.Id { + if t.Client.Id == v.Id { v.Flow.InletFlow += t.Flow.InletFlow v.Flow.ExportFlow += t.Flow.ExportFlow } @@ -236,12 +215,12 @@ func dealClientData(list []*utils.Client) { //根据客户端id删除其所属的所有隧道和域名 func DelTunnelAndHostByClientId(clientId int) { for _, v := range CsvDb.Tasks { - if v.ClientId == clientId { + if v.Client.Id == clientId { DelTask(v.Id) } } for _, v := range CsvDb.Hosts { - if v.ClientId == clientId { + if v.Client.Id == clientId { CsvDb.DelHost(v.Host) } } diff --git a/server/socks5.go b/server/socks5.go index f8f9211..4c14c85 100755 --- a/server/socks5.go +++ b/server/socks5.go @@ -141,7 +141,7 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *utils } else { 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) return } @@ -160,7 +160,7 @@ func (s *Sock5ModeServer) handleConnect(c net.Conn) { proxyConn, err := s.doConnect(c, connectMethod) defer func() { if s.config.Mux && proxyConn != nil { - s.bridge.ReturnTunnel(proxyConn, s.config.ClientId) + s.bridge.ReturnTunnel(proxyConn, s.task.Client.Id) } }() if err != nil { @@ -198,7 +198,7 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) { proxyConn, err := s.doConnect(c, associateMethod) defer func() { if s.config.Mux && proxyConn != nil { - s.bridge.ReturnTunnel(proxyConn, s.config.ClientId) + s.bridge.ReturnTunnel(proxyConn, s.task.Client.Id) } }() if err != nil { @@ -285,7 +285,7 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error { //start func (s *Sock5ModeServer) Start() 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 { return err } @@ -309,10 +309,11 @@ func (s *Sock5ModeServer) Close() error { } //new -func NewSock5ModeServer(bridge *bridge.Tunnel, cnf *utils.ServerConfig) *Sock5ModeServer { +func NewSock5ModeServer(bridge *bridge.Bridge, task *utils.Tunnel) *Sock5ModeServer { s := new(Sock5ModeServer) s.bridge = bridge - s.config = cnf + s.task = task + s.config = utils.DeepCopyConfig(task.Config) if s.config.U != "" && s.config.P != "" { s.isVerify = true } else { diff --git a/server/tcp.go b/server/tcp.go index d47ae43..810123a 100755 --- a/server/tcp.go +++ b/server/tcp.go @@ -20,11 +20,12 @@ type TunnelModeServer struct { } //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.bridge = bridge s.process = process - s.config = cnf + s.task = task + s.config = utils.DeepCopyConfig(task.Config) 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 { 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 { 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 err error defer func() { 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) return err } @@ -115,7 +116,7 @@ func (s *WebServer) Start() { } //new -func NewWebServer(bridge *bridge.Tunnel) *WebServer { +func NewWebServer(bridge *bridge.Bridge) *WebServer { s := new(WebServer) s.bridge = bridge return s @@ -131,9 +132,10 @@ func (s *HostServer) Start() error { return nil } -func NewHostServer(cnf *utils.ServerConfig) *HostServer { +func NewHostServer(task *utils.Tunnel) *HostServer { s := new(HostServer) - s.config = cnf + s.task = task + s.config = utils.DeepCopyConfig(task.Config) return s } diff --git a/server/udp.go b/server/udp.go index 7ede79e..72661d0 100755 --- a/server/udp.go +++ b/server/udp.go @@ -15,18 +15,19 @@ type UdpModeServer struct { 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.bridge = bridge s.udpMap = make(map[string]*utils.Conn) - s.config = cnf + s.task = task + s.config = utils.DeepCopyConfig(task.Config) return s } //开始 func (s *UdpModeServer) Start() 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 { return err } @@ -45,14 +46,14 @@ func (s *UdpModeServer) Start() error { return nil } -//TODO:效率问题有待解决 +//TODO:效率问题有待解决--->建立稳定通道,重复利用,提高效率,下个版本 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 { log.Println(err) 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() return } @@ -60,7 +61,7 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) { defer func() { if conn != nil && s.config.Mux { 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 { conn.Close() } @@ -70,7 +71,6 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) { buf := utils.BufPoolUdp.Get().([]byte) out, err := conn.ReadFrom(buf, s.config.CompressDecode, s.config.Crypt) if err != nil || err == io.EOF { - log.Println("revieve error:", err) return } s.listener.WriteToUDP(buf[:out], addr) diff --git a/utils/file.go b/utils/file.go index f892fa6..38eac89 100644 --- a/utils/file.go +++ b/utils/file.go @@ -22,7 +22,7 @@ type Flow struct { } type Client struct { - Cnf *ServerConfig + Cnf *Config Id int //id VerifyKey string //验证密钥 Addr string //客户端ip地址 @@ -32,35 +32,36 @@ type Client struct { Flow *Flow } -type ServerConfig struct { - TcpPort int //服务端与客户端通信端口 - VerifyKey string - Mode string //启动方式 - Target string //目标 +type Tunnel struct { + Id int //Id + TcpPort int //服务端与客户端通信端口 + Mode string //启动方式 + Target string //目标 + Status bool //是否开启 + Client *Client //所属客户端id + Flow *Flow + Config *Config + UseClientCnf bool //是否继承客户端配置 + Remark string //备注 +} + +type Config struct { U string //socks5验证用户名 P string //socks5验证密码 Compress string //压缩方式 - Start int //是否开启 - IsRun int //是否在运行 - ClientStatus int //客s户端状态 Crypt bool //是否加密 Mux bool //是否加密 CompressEncode int //加密方式 CompressDecode int //解密方式 - Id int //Id - ClientId int //所属客户端id - UseClientCnf bool //是否继承客户端配置 - Flow *Flow - Remark string //备注 } -type HostList struct { - ClientId int //服务端与客户端通信端口 +type Host struct { Host string //启动方式 Target string //目标 HeaderChange string //host修改 HostChange string //host修改 Flow *Flow + Client *Client Remark string //备注 } @@ -70,19 +71,19 @@ func NewCsv() *Csv { } type Csv struct { - Tasks []*ServerConfig + Tasks []*Tunnel Path string - Hosts []*HostList //域名列表 - Clients []*Client //客户端 - ClientIncreaseId int //客户端id - TaskIncreaseId int //任务自增ID + Hosts []*Host //域名列表 + Clients []*Client //客户端 + ClientIncreaseId int //客户端id + TaskIncreaseId int //任务自增ID sync.Mutex } func (s *Csv) Init() { + s.LoadClientFromCsv() s.LoadTaskFromCsv() s.LoadHostFromCsv() - s.LoadClientFromCsv() } func (s *Csv) StoreTasksToCsv() { @@ -98,16 +99,16 @@ func (s *Csv) StoreTasksToCsv() { strconv.Itoa(task.TcpPort), task.Mode, task.Target, - task.U, - task.P, - task.Compress, - strconv.Itoa(task.Start), - GetStrByBool(task.Crypt), - GetStrByBool(task.Mux), - strconv.Itoa(task.CompressEncode), - strconv.Itoa(task.CompressDecode), + task.Config.U, + task.Config.P, + task.Config.Compress, + utils.GetStrByBool(task.Status), + GetStrByBool(task.Config.Crypt), + GetStrByBool(task.Config.Mux), + strconv.Itoa(task.Config.CompressEncode), + strconv.Itoa(task.Config.CompressDecode), strconv.Itoa(task.Id), - strconv.Itoa(task.ClientId), + strconv.Itoa(task.Client.Id), strconv.FormatBool(task.UseClientCnf), task.Remark, } @@ -143,27 +144,31 @@ func (s *Csv) LoadTaskFromCsv() { if err != nil { log.Fatal("配置文件打开错误:", path) } - var tasks []*ServerConfig + var tasks []*Tunnel // 将每一行数据保存到内存slice中 for _, item := range records { - post := &ServerConfig{ - TcpPort: GetIntNoErrByStr(item[0]), - Mode: item[1], - Target: item[2], - U: item[3], - P: item[4], - Compress: item[5], - Start: GetIntNoErrByStr(item[6]), - Crypt: GetBoolByStr(item[7]), - Mux: GetBoolByStr(item[8]), - CompressEncode: GetIntNoErrByStr(item[9]), - CompressDecode: GetIntNoErrByStr(item[10]), - Id: GetIntNoErrByStr(item[11]), - ClientId: GetIntNoErrByStr(item[12]), - UseClientCnf: GetBoolByStr(item[13]), - Remark: item[14], + post := &Tunnel{ + TcpPort: GetIntNoErrByStr(item[0]), + Mode: item[1], + Target: item[2], + Config: &Config{ + U: item[3], + P: item[4], + Compress: item[5], + Crypt: GetBoolByStr(item[7]), + Mux: GetBoolByStr(item[8]), + CompressEncode: GetIntNoErrByStr(item[9]), + CompressDecode: GetIntNoErrByStr(item[10]), + }, + Status: utils.GetBoolByStr(item[6]), + Id: GetIntNoErrByStr(item[11]), + UseClientCnf: GetBoolByStr(item[13]), + Remark: item[14], } post.Flow = new(Flow) + if post.Client, err = s.GetClient(GetIntNoErrByStr(item[12])); err != nil { + continue + } tasks = append(tasks, post) if post.Id > s.TaskIncreaseId { s.TaskIncreaseId = post.Id @@ -191,13 +196,13 @@ func (s *Csv) GetIdByVerifyKey(vKey string, addr string) (int, error) { return 0, errors.New("not found") } -func (s *Csv) NewTask(t *ServerConfig) { +func (s *Csv) NewTask(t *Tunnel) { t.Flow = new(Flow) s.Tasks = append(s.Tasks, t) s.StoreTasksToCsv() } -func (s *Csv) UpdateTask(t *ServerConfig) error { +func (s *Csv) UpdateTask(t *Tunnel) error { for k, v := range s.Tasks { if v.Id == t.Id { s.Tasks = append(s.Tasks[:k], s.Tasks[k+1:]...) @@ -220,7 +225,7 @@ func (s *Csv) DelTask(id int) error { 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 { if v.Id == id { return @@ -245,7 +250,7 @@ func (s *Csv) StoreHostToCsv() { record := []string{ host.Host, host.Target, - strconv.Itoa(host.ClientId), + strconv.Itoa(host.Client.Id), host.HeaderChange, host.HostChange, host.Remark, @@ -274,7 +279,7 @@ func (s *Csv) LoadClientFromCsv() { Addr: item[2], Remark: item[3], Status: GetBoolByStr(item[4]), - Cnf: &ServerConfig{ + Cnf: &Config{ U: item[5], P: item[6], Crypt: GetBoolByStr(item[7]), @@ -297,17 +302,19 @@ func (s *Csv) LoadHostFromCsv() { if err != nil { log.Fatal("配置文件打开错误:", path) } - var hosts []*HostList + var hosts []*Host // 将每一行数据保存到内存slice中 for _, item := range records { - post := &HostList{ - ClientId: GetIntNoErrByStr(item[2]), + post := &Host{ Host: item[0], Target: item[1], HeaderChange: item[3], HostChange: item[4], Remark: item[5], } + if post.Client, err = s.GetClient(GetIntNoErrByStr(item[2])); err != nil { + continue + } post.Flow = new(Flow) hosts = append(hosts, post) } @@ -325,14 +332,14 @@ func (s *Csv) DelHost(host string) error { return errors.New("不存在") } -func (s *Csv) NewHost(t *HostList) { +func (s *Csv) NewHost(t *Host) { t.Flow = new(Flow) s.Hosts = append(s.Hosts, t) s.StoreHostToCsv() } -func (s *Csv) UpdateHost(t *HostList) error { +func (s *Csv) UpdateHost(t *Host) error { for k, v := range s.Hosts { if v.Host == t.Host { s.Hosts = append(s.Hosts[:k], s.Hosts[k+1:]...) @@ -344,11 +351,11 @@ func (s *Csv) UpdateHost(t *HostList) error { return errors.New("不存在") } -func (s *Csv) GetHostList(start, length int, id int) ([]*HostList, int) { - list := make([]*HostList, 0) +func (s *Csv) GetHost(start, length int, id int) ([]*Host, int) { + list := make([]*Host, 0) var cnt int for _, v := range s.Hosts { - if id == 0 || v.ClientId == id { + if id == 0 || v.Client.Id == id { cnt++ if start--; start < 0 { if length--; length > 0 { @@ -461,27 +468,15 @@ func GetCsvDb() *Csv { return CsvDb } -//深拷贝serverConfig -func DeepCopyConfig(c *ServerConfig) *ServerConfig { - return &ServerConfig{ - TcpPort: c.TcpPort, - VerifyKey: c.VerifyKey, - Mode: c.Mode, - Target: c.Target, +//深拷贝Tunnel +func DeepCopyConfig(c *Config) *Config { + return &Config{ U: c.U, P: c.P, Compress: c.Compress, - Start: c.Start, - IsRun: c.IsRun, - ClientStatus: c.ClientStatus, Crypt: c.Crypt, Mux: c.Mux, CompressEncode: c.CompressEncode, CompressDecode: c.CompressDecode, - Id: c.Id, - ClientId: c.ClientId, - UseClientCnf: c.UseClientCnf, - Flow: c.Flow, - Remark: c.Remark, } } diff --git a/utils/util.go b/utils/util.go index 89b9b11..a717802 100755 --- a/utils/util.go +++ b/utils/util.go @@ -240,6 +240,5 @@ func ReadAllFromFile(filePth string) ([]byte, error) { if err != nil { return nil, err } - return ioutil.ReadAll(f) } diff --git a/web/controllers/client.go b/web/controllers/client.go index c7d943d..4058b63 100644 --- a/web/controllers/client.go +++ b/web/controllers/client.go @@ -33,7 +33,7 @@ func (s *ClientController) Add() { Id: server.CsvDb.GetClientId(), Status: true, Remark: s.GetString("Remark"), - Cnf: &utils.ServerConfig{ + Cnf: &utils.Config{ U: s.GetString("u"), P: s.GetString("p"), Compress: s.GetString("compress"), diff --git a/web/controllers/index.go b/web/controllers/index.go index d827542..1fcfdaf 100755 --- a/web/controllers/index.go +++ b/web/controllers/index.go @@ -57,11 +57,11 @@ func (s *IndexController) All() { s.display("index/list") } -func (s *IndexController) GetServerConfig() { +func (s *IndexController) GetTunnel() { start, length := s.GetAjaxParams() taskType := s.GetString("type") 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) } @@ -72,22 +72,26 @@ func (s *IndexController) Add() { s.SetInfo("新增") s.display() } else { - t := &utils.ServerConfig{ - TcpPort: s.GetIntNoErr("port"), - Mode: s.GetString("type"), - Target: s.GetString("target"), - U: s.GetString("u"), - P: s.GetString("p"), - Compress: s.GetString("compress"), - Crypt: s.GetBoolNoErr("crypt"), - Mux: s.GetBoolNoErr("mux"), - IsRun: 0, + t := &utils.Tunnel{ + TcpPort: s.GetIntNoErr("port"), + Mode: s.GetString("type"), + Target: s.GetString("target"), + Config: &utils.Config{ + U: s.GetString("u"), + P: s.GetString("p"), + Compress: s.GetString("compress"), + Crypt: s.GetBoolNoErr("crypt"), + Mux: s.GetBoolNoErr("mux"), + }, Id: server.CsvDb.GetTaskId(), - ClientId: s.GetIntNoErr("client_id"), UseClientCnf: s.GetBoolNoErr("use_client"), - Start: 1, + Status: true, 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) if err := server.AddTask(t); err != nil { s.AjaxErr(err.Error()) @@ -115,12 +119,12 @@ func (s *IndexController) Edit() { t.Mode = s.GetString("type") t.Target = s.GetString("target") t.Id = id - t.ClientId = s.GetIntNoErr("client_id") - t.U = s.GetString("u") - t.P = s.GetString("p") - t.Compress = s.GetString("compress") - t.Crypt = s.GetBoolNoErr("crypt") - t.Mux = s.GetBoolNoErr("mux") + t.Client.Id = s.GetIntNoErr("client_id") + t.Config.U = s.GetString("u") + t.Config.P = s.GetString("p") + t.Config.Compress = s.GetString("compress") + t.Config.Crypt = s.GetBoolNoErr("crypt") + t.Config.Mux = s.GetBoolNoErr("mux") t.UseClientCnf = s.GetBoolNoErr("use_client") t.Remark = s.GetString("remark") server.CsvDb.UpdateTask(t) @@ -162,7 +166,7 @@ func (s *IndexController) HostList() { } else { start, length := s.GetAjaxParams() 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) } } @@ -182,8 +186,10 @@ func (s *IndexController) AddHost() { s.SetInfo("新增") s.display("index/hadd") } else { - h := &utils.HostList{ - ClientId: s.GetIntNoErr("client_id"), + h := &utils.Host{ + Client: &utils.Client{ + Id: s.GetIntNoErr("client_id"), + }, Host: s.GetString("host"), Target: s.GetString("target"), HeaderChange: s.GetString("header"), @@ -199,7 +205,7 @@ func (s *IndexController) EditHost() { host := s.GetString("host") if s.Ctx.Request.Method == "GET" { s.Data["menu"] = "host" - if h, _, err := server.GetKeyByHost(host); err != nil { + if h, err := server.GetInfoByHost(host); err != nil { s.error() } else { s.Data["h"] = h @@ -207,10 +213,10 @@ func (s *IndexController) EditHost() { s.SetInfo("修改") s.display("index/hedit") } else { - if h, _, err := server.GetKeyByHost(host); err != nil { + if h, err := server.GetInfoByHost(host); err != nil { s.error() } else { - h.ClientId = s.GetIntNoErr("client_id") + h.Client.Id = s.GetIntNoErr("client_id") h.Host = s.GetString("nhost") h.Target = s.GetString("target") h.HeaderChange = s.GetString("header") diff --git a/web/views/index/edit.html b/web/views/index/edit.html index 176902d..e3865cf 100755 --- a/web/views/index/edit.html +++ b/web/views/index/edit.html @@ -31,7 +31,7 @@ </div> <div class="form-group" id="client_id"> <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"> </div> <div class="form-group" id="use_client"> @@ -44,32 +44,32 @@ <div class="form-group" id="compress"> <label class="control-label">数据压缩方式(所有模式均支持)</label> <select class="form-control" name="compress"> - <option {{if eq "" .t.Compress}}selected{{end}} value="">不压缩</option> - <option {{if eq "snappy" .t.Compress}}selected{{end}} value="snappy">snappy压缩</option> + <option {{if eq "" .t.Config.Compress}}selected{{end}} value="">不压缩</option> + <option {{if eq "snappy" .t.Config.Compress}}selected{{end}} value="snappy">snappy压缩</option> </select> </div> <div class="form-group" id="crypt"> <label class="control-label">是否加密传输(所有模式均支持)</label> <select class="form-control" name="crypt"> - <option {{if eq false .t.Crypt}}selected{{end}} value="0">不加密</option> - <option {{if eq true .t.Crypt}}selected{{end}} value="1">加密</option> + <option {{if eq false .t.Config.Crypt}}selected{{end}} value="0">不加密</option> + <option {{if eq true .t.Config.Crypt}}selected{{end}} value="1">加密</option> </select> </div> <div class="form-group" id="mux"> <label class="control-label">是否启用TCP复用(所有模式均支持)</label> <select class="form-control" name="mux"> - <option {{if eq false .t.Mux}}selected{{end}} value="0">不启用</option> - <option {{if eq true .t.Mux}}selected{{end}} value="1">启用</option> + <option {{if eq false .t.Config.Mux}}selected{{end}} value="0">不启用</option> + <option {{if eq true .t.Config.Mux}}selected{{end}} value="1">启用</option> </select> </div> <div class="form-group" id="u"> <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="不填则无需验证"> </div> <div class="form-group" id="p"> <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="不填则无需验证"> </div> </form> diff --git a/web/views/index/hedit.html b/web/views/index/hedit.html index 2f2704e..d9d83ed 100644 --- a/web/views/index/hedit.html +++ b/web/views/index/hedit.html @@ -15,7 +15,7 @@ </div> <div class="form-group"> <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"> </div> <div class="form-group"> diff --git a/web/views/index/hlist.html b/web/views/index/hlist.html index 6e42ae1..ce383e2 100755 --- a/web/views/index/hlist.html +++ b/web/views/index/hlist.html @@ -10,6 +10,11 @@ <th>host</th> <th>内网目标</th> <th>host改写</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">', columns: [ //这个是显示到界面上的个数据 格式为 {data:'显示的字段名'} - {data: 'ClientId'}, + {data: 'Remark'}, {data: 'Remark'}, {data: 'Host'}, {data: 'Target'}, {data: 'HostChange'}, {data: 'HostChange'}, {data: 'HostChange'}, + {data: 'HostChange'}, + {data: 'HostChange'}, + {data: 'HostChange'}, + {data: 'HostChange'}, + {data: 'HostChange'}, {data: 'Target'}, ], bFilter: false, @@ -88,6 +98,12 @@ + ' </div>' } }, + { + targets: 1, + render: function (data, type, row, meta) { + return row.Client.Id + } + }, { targets: -2, render: function (data, type, row, meta) { @@ -99,6 +115,46 @@ render: function (data, type, row, meta) { 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: [] diff --git a/web/views/index/list.html b/web/views/index/list.html index 498cd6a..5a8fd56 100755 --- a/web/views/index/list.html +++ b/web/views/index/list.html @@ -102,7 +102,7 @@ autoWidth: false, ordering: false, ajax: { - url: '/index/getserverconfig?type={{.type}}' + "&client_id=" +{{.client_id}}, + url: '/index/gettunnel?type={{.type}}' + "&client_id=" +{{.client_id}}, type: 'POST' }, dom: '<"top"fl><"toolbar">rt<"bottom"ip><"clear">', @@ -118,7 +118,7 @@ {data: 'U'}, {data: 'P'}, {data: 'ClientStatus'}, - {data: 'IsRun'}, + {data: 'Status'}, {data: 'ExportFlow'}, {data: 'InletFlow'}, {data: "Id"} @@ -127,7 +127,7 @@ columnDefs: [{ targets: -1, 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>" } else { 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>' + 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, render: function (data, type, row, meta) { - if (data == 0) { + if (data == false) { return "<span class=\"badge badge-pill badge-secondary\">暂停</span>" } else { return "<span class=\"badge badge-pill badge-success\">正常</span>" @@ -151,7 +183,12 @@ { targets: -9, 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 "不加密" } else { return "加密" @@ -161,7 +198,12 @@ { targets: -8, 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 "不启用" } else { return "启用" @@ -171,7 +213,7 @@ { targets: -5, render: function (data, type, row, meta) { - if (data == 0) { + if (row.Client.IsConnect == false) { return "<span class=\"badge badge-pill badge-secondary\">离线</span>" } else { return "<span class=\"badge badge-pill badge-success\">在线</span>"