浏览代码

客户端服务端分离

刘河 6 年之前
父节点
当前提交
1f61b99387
共有 46 个文件被更改,包括 1062 次插入1431 次删除
  1. 18 126
      README.md
  2. 241 0
      bridge/bridge.go
  3. 27 60
      client/client.go
  4. 27 0
      cmd/proxy_client.go
  5. 47 0
      cmd/proxy_server.go
  6. 1 1
      conf/app.conf
  7. 1 1
      conf/hosts.csv
  8. 3 1
      conf/tasks.csv
  9. 0 228
      lib/bridge.go
  10. 0 201
      lib/init.go
  11. 0 326
      lib/tcp.go
  12. 0 330
      lib/util.go
  13. 0 10
      main.go
  14. 10 74
      server/file.go
  15. 209 0
      server/server.go
  16. 16 13
      server/socks5.go
  17. 191 0
      server/tcp.go
  18. 11 8
      server/udp.go
  19. 21 19
      utils/conn.go
  20. 2 2
      utils/crypt.go
  21. 204 0
      utils/util.go
  22. 4 3
      web/controllers/base.go
  23. 24 23
      web/controllers/index.go
  24. 0 0
      web/controllers/login.go
  25. 1 1
      web/routers/router.go
  26. 0 0
      web/static/css/font-awesome.min.css
  27. 0 0
      web/static/css/main.css
  28. 0 0
      web/static/fonts/FontAwesome.otf
  29. 0 0
      web/static/fonts/fontawesome-webfont.eot
  30. 0 0
      web/static/fonts/fontawesome-webfont.svg
  31. 0 0
      web/static/fonts/fontawesome-webfont.ttf
  32. 0 0
      web/static/fonts/fontawesome-webfont.woff
  33. 0 0
      web/static/fonts/fontawesome-webfont.woff2
  34. 0 0
      web/static/img/48.jpg
  35. 0 0
      web/static/img/favicon.ico
  36. 0 0
      web/static/js/datatables.min.js
  37. 0 0
      web/static/js/main.js
  38. 2 2
      web/views/index/add.html
  39. 2 2
      web/views/index/edit.html
  40. 0 0
      web/views/index/hadd.html
  41. 0 0
      web/views/index/hlist.html
  42. 0 0
      web/views/index/index.html
  43. 0 0
      web/views/index/list.html
  44. 0 0
      web/views/login/index.html
  45. 0 0
      web/views/public/error.html
  46. 0 0
      web/views/public/layout.html

+ 18 - 126
README.md

@@ -11,19 +11,17 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
 ![image](https://github.com/cnlh/easyProxy/blob/master/image/web.png?raw=true)
 1. web管理模式,可配置多条tcp、udp隧道,多个域名代理等等----> [web管理模式](#web管理模式)
 
-2. 内网多站点配合代理。----> [http反向代理请求](#http代理请求)
 
-3. 想在外网通过ssh连接内网的机器,做云服务器到内网服务器端口的映射,或者做微信公众号开发、小程序开发等---->[tcp隧道模式](#tcp隧道模式)
+2. 想在外网通过ssh连接内网的机器,做云服务器到内网服务器端口的映射,或者做微信公众号开发、小程序开发等---->[tcp隧道模式](#tcp隧道模式)
 
-4. 在非内网环境下使用内网dns,或者需要通过udp访问内网机器等---->[udp隧道模式](#udp隧道模式)
+3. 在非内网环境下使用内网dns,或者需要通过udp访问内网机器等---->[udp隧道模式](#udp隧道模式)
 
-5. 在外网使用HTTP代理访问内网站点---->[http代理模式](#http代理模式)
+4. 在外网使用HTTP代理访问内网站点---->[http代理模式](#http代理模式)
 
-6. 搭建一个内网穿透ss,在外网如同使用内网vpn一样访问内网资源或者设备----> [socks5代理模式](#socks5代理模式)
+5. 搭建一个内网穿透ss,在外网如同使用内网vpn一样访问内网资源或者设备----> [socks5代理模式](#socks5代理模式)
 
 ## 特点
 - [x] 支持snappy压缩,减小传输过程流量消耗
-- [x] 支持多站点配置,兼容多个内网网站,可处理相互之间的跳转包含关系
 - [x] 断线自动重连
 - [x] 支持多路传输,提高并发
 - [x] 跨站自动匹配替换
@@ -44,13 +42,12 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
 2. [web管理模式](#web管理模式)(多隧道时推荐)
 3. [tcp隧道模式](#tcp隧道模式)
 4. [udp隧道模式](#udp隧道模式)
-5. [http反向代理请求](#http代理请求)
-6. [socks5代理模式](#socks5代理模式)
-7. [http代理模式](#http代理模式)
-8. [数据压缩支持](#数据压缩支持)
-9. [站点密码保护](#站点保护)
-10. [加密传输](#加密传输)
-11. [TCP多路复用](#多路复用)
+5. [socks5代理模式](#socks5代理模式)
+6. [http代理模式](#http代理模式)
+7. [数据压缩支持](#数据压缩支持)
+8. [站点密码保护](#站点保护)
+9. [加密传输](#加密传输)
+10. [TCP多路复用](#多路复用)
 11. [配置文件说明](#配置文件)
 
 ## 安装
@@ -58,13 +55,14 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
 1. release安装
 > https://github.com/cnlh/easyProxy/releases
 
-下载对应的系统版本即可,服务端和客户端共用一个程序,go语言开发,无需任何第三方依赖
+下载对应的系统版本即可,服务端和客户端是单独的,go语言开发,无需任何第三方依赖
 
 2. 源码安装
 - 安装源码
 > go get github.com/cnlh/easyProxy
 - 编译
-> go build
+> go build cmd/proxy_server.go
+> go build cmd/proxy_client.go
 
 ## web管理模式
 
@@ -72,6 +70,9 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
 ### 介绍
 
 可在网页上配置和管理各个tcp、udp隧道、内网站点代理等等,功能极为强大,操作也非常方便。
+
+**提示:使用web模式时,服务端执行文件必须在项目根目录,否则无法正确加载配置文件**
+
 ### 使用
 
 **有两种模式:**
@@ -218,116 +219,7 @@ target | 目标地址,格式如上
 ./easyProxy -server=ip:port -vkey=DKibZF5TXvic1g3kY
 ```
 
-## http代理请求
-
-### 场景及原理
-
-较为适用于http,也就是web站点的穿透,服务端与客户端之间建立连接,服务端收到http请求后,将请求发送到客户端,客户端再执行这个请求,并将结果返回给服务端,服务端收到后再返回。
-
-<html>
-<span style="color:red">特点:支持同时代理多个站点,不同站点之间有联系还可以实现匹配替换</span>
-</html>
-
-![image](https://github.com/cnlh/easyProxy/blob/master/image/http.png?raw=true)
-
-**最终效果**:
-- 访问a.server.com和访问10.1.50.203的80端口相同
-- 访问b.server.com和访问10.1.50.202的80端口相同
-- 访问c.server.com和访问10.1.50.201的80端口相同
-### 使用
-- 服务端
-
-```
-./easyProxy -mode=httpServer -vkey=DKibZF5TXvic1g3kY -tcpport=8284 -httpport=8024
-```
-
-名称 | 含义
----|---
-mode | 运行模式
-vkey | 验证密钥
-tcpport | 服务端与客户端通信端口
-httpport | 代理的http端口(与nginx配合使用)
-
-- 客户端
-
-```
-建立配置文件 config.json
-```
-
-
-```
-./easyProxy -server=ip:port -config=config.json -vkey=DKibZF5TXvic1g3kY
-```
-
-
- 名称 | 含义
----|---
-config | 配置文件路径
-### 配置文件config.json
-
-```
-{
-  "SiteList": [
-    {
-      "host": "a.ourcauc.com",
-      "url": "10.1.50.203",
-      "port": 80
-    },
-    {
-      "host": "b.ourcauc.com",
-      "url": "10.1.50.202",
-      "port": 80
-    },
-    {
-      "host": "c.ourcauc.com",
-      "url": "10.1.50.203",
-      "port": 80
-    }
-  ],
-  "Replace": 0
-}
-```
- 名称 | 含义
----|---
-SiteList | 本地解析的域名列表
-host | 域名地址
-url | 内网代理的地址
-port | 内网代理的地址对应的端口
-Replace | 是否自动匹配替换[(查看场景)](https://github.com/cnlh/easyProxy/issues/1)
-
-
-### nginx代理配置示例
-```
-server {
-    listen 80;
-    server_name a.ourcauc.com b.ourcauc.com c.ourcauc.com ;
-    location / {
-            proxy_set_header X-Real-IP $remote_addr;
-            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-            proxy_set_header Host  $http_host;
-            proxy_set_header X-Nginx-Proxy true;
-            proxy_set_header Connection "";
-            proxy_pass http://127.0.0.1:8024;
-        }
-}
-```
-## 域名配置示例
-> -a	    A	    123.206.77.88
-
-> -b	    A	    123.206.77.88
-
-> -c	    A	    123.206.77.88
-
-### 跨站自动匹配替换说明
-
-例如,访问:a.ourcauc.com,该页面里面有一个超链接为10.1.50.202:80,将根据配置文件自动该将url替换为b.ourcauc.com,以达到跨站也可访问的效果,但需要提前在配置文件中配置这些站点。
-
-如需开启,请加配置文件Replace值设置为1
->注意:开启可能导致不应该被替换的内容被替换,请谨慎开启
-
-### 二级域名示范
 
-[二级域名](https://github.com/cnlh/easyProxy/wiki/%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B)
 
 
 ## socks5代理模式
@@ -422,9 +314,9 @@ httpport | http代理连接端口
 - 所有模式均支持数据压缩,可以与加密同时使用
 
 
-- 在server端加上参数 -compress=snappy(或在web中设置),例如在TCP隧道模式
+- 在server端加上参数 -compress=snappy(或在web管理中设置)
 ```
-./easyProxy -mode=tunnelServer -vkey=DKibZF5TXvic1g3kY -tcpport=8284 -httpport=8024 -target=10.1.50.203:80 -compress=snappy
+-compress=snappy
 ```
 
 ## 加密传输

+ 241 - 0
bridge/bridge.go

@@ -0,0 +1,241 @@
+package bridge
+
+import (
+	"errors"
+	"github.com/cnlh/easyProxy/utils"
+	"log"
+	"net"
+	"sync"
+	"time"
+)
+
+type list struct {
+	connList chan *utils.Conn
+}
+
+func (l *list) Add(c *utils.Conn) {
+	l.connList <- c
+}
+
+func (l *list) Pop() *utils.Conn {
+	return <-l.connList
+}
+func (l *list) Len() int {
+	return len(l.connList)
+}
+
+func newList() *list {
+	l := new(list)
+	l.connList = make(chan *utils.Conn, 1000)
+	return l
+}
+
+type Tunnel struct {
+	TunnelPort int                    //通信隧道端口
+	listener   *net.TCPListener       //server端监听
+	SignalList map[string]*list       //通信
+	TunnelList map[string]*list       //隧道
+	RunList    map[string]interface{} //运行中的任务
+	lock       sync.Mutex
+	tunnelLock sync.Mutex
+}
+
+func NewTunnel(tunnelPort int, runList map[string]interface{}) *Tunnel {
+	t := new(Tunnel)
+	t.TunnelPort = tunnelPort
+	t.SignalList = make(map[string]*list)
+	t.TunnelList = make(map[string]*list)
+	t.RunList = runList
+	return t
+}
+
+func (s *Tunnel) StartTunnel() error {
+	var err error
+	s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.TunnelPort, ""})
+	if err != nil {
+		return err
+	}
+	go s.tunnelProcess()
+	return nil
+}
+
+//tcp server
+func (s *Tunnel) tunnelProcess() error {
+	var err error
+	for {
+		conn, err := s.listener.Accept()
+		if err != nil {
+			log.Println(err)
+			continue
+		}
+		go s.cliProcess(utils.NewConn(conn))
+	}
+	return err
+}
+
+//验证失败,返回错误验证flag,并且关闭连接
+func (s *Tunnel) verifyError(c *utils.Conn) {
+	c.Conn.Write([]byte(utils.VERIFY_EER))
+	c.Conn.Close()
+}
+
+func (s *Tunnel) 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 {
+		log.Println("客户端读超时。客户端地址为::", c.Conn.RemoteAddr())
+		c.Conn.Close()
+		return err
+	}
+	if !s.verify(string(vval)) {
+		log.Println("当前客户端连接校验错误,关闭此客户端:", c.Conn.RemoteAddr())
+		s.verifyError(c)
+		return errors.New("验证错误")
+	}
+	log.Println("客户端连接成功: ", c.Conn.RemoteAddr())
+	c.Conn.(*net.TCPConn).SetReadDeadline(time.Time{})
+	//做一个判断 添加到对应的channel里面以供使用
+	if flag, err := c.ReadFlag(); err != nil {
+		return err
+	} else {
+		return s.typeDeal(flag, c, string(vval))
+	}
+}
+
+//tcp连接类型区分
+func (s *Tunnel) typeDeal(typeVal string, c *utils.Conn, cFlag string) error {
+	switch typeVal {
+	case utils.WORK_MAIN:
+		s.addList(s.SignalList, c, cFlag)
+	case utils.WORK_CHAN:
+		s.addList(s.TunnelList, c, cFlag)
+	default:
+		return errors.New("无法识别")
+	}
+	c.SetAlive()
+	return nil
+}
+
+//加到对应的list中
+func (s *Tunnel) addList(m map[string]*list, c *utils.Conn, cFlag string) {
+	s.lock.Lock()
+	if v, ok := m[cFlag]; ok {
+		v.Add(c)
+	} else {
+		l := newList()
+		l.Add(c)
+		m[cFlag] = l
+	}
+	s.lock.Unlock()
+}
+
+//新建隧道
+func (s *Tunnel) newChan(cFlag string) error {
+	if err := s.wait(s.SignalList, cFlag); err != nil {
+		return err
+	}
+retry:
+	connPass := s.SignalList[cFlag].Pop()
+	_, err := connPass.Conn.Write([]byte("chan"))
+	if err != nil {
+		log.Println(err)
+		goto retry
+	}
+	s.SignalList[cFlag].Add(connPass)
+	return nil
+}
+
+//得到一个tcp隧道
+func (s *Tunnel) GetTunnel(cFlag string, en, de int, crypt, mux bool) (c *utils.Conn, err error) {
+	s.tunnelLock.Lock()
+	if v, ok := s.TunnelList[cFlag]; !ok || v.Len() < 3 { //新建通道
+		go s.newChan(cFlag)
+	}
+retry:
+	if err = s.wait(s.TunnelList, cFlag); err != nil {
+		return
+	}
+	c = s.TunnelList[cFlag].Pop()
+	if _, err = c.WriteTest(); err != nil {
+		c.Close()
+		goto retry
+	}
+	c.WriteConnInfo(en, de, crypt, mux)
+	s.tunnelLock.Unlock()
+	return
+}
+
+//得到一个通信通道
+func (s *Tunnel) GetSignal(cFlag string) (err error, conn *utils.Conn) {
+	if v, ok := s.SignalList[cFlag]; !ok || v.Len() == 0 {
+		err = errors.New("客户端未连接")
+		return
+	}
+	conn = s.SignalList[cFlag].Pop()
+	return
+}
+
+//重回slice 复用
+func (s *Tunnel) ReturnSignal(conn *utils.Conn, cFlag string) {
+	if v, ok := s.SignalList[cFlag]; ok {
+		v.Add(conn)
+	}
+}
+
+//重回slice 复用
+func (s *Tunnel) ReturnTunnel(conn *utils.Conn, cFlag string) {
+	if v, ok := s.TunnelList[cFlag]; ok {
+		utils.FlushConn(conn.Conn)
+		v.Add(conn)
+	}
+}
+
+//删除通信通道
+func (s *Tunnel) DelClientSignal(cFlag string) {
+	s.delClient(cFlag, s.SignalList)
+}
+
+//删除隧道
+func (s *Tunnel) DelClientTunnel(cFlag string) {
+	s.delClient(cFlag, s.TunnelList)
+}
+
+func (s *Tunnel) delClient(cFlag string, l map[string]*list) {
+	if t := l[utils.Getverifyval(cFlag)]; t != nil {
+		for {
+			if t.Len() <= 0 {
+				break
+			}
+			t.Pop().Close()
+		}
+		delete(l, utils.Getverifyval(cFlag))
+	}
+}
+
+//等待
+func (s *Tunnel) wait(m map[string]*list, cFlag string) error {
+	ticker := time.NewTicker(time.Millisecond * 100)
+	stop := time.After(time.Second * 10)
+loop:
+	for {
+		select {
+		case <-ticker.C:
+			if _, ok := m[cFlag]; ok {
+				ticker.Stop()
+				break loop
+			}
+		case <-stop:
+			return errors.New("client key: " + cFlag + ",err: get client conn timeout")
+		}
+	}
+	return nil
+}
+
+func (s *Tunnel) verify(vKeyMd5 string) bool {
+	for k := range s.RunList {
+		if utils.Getverifyval(k) == vKeyMd5 {
+			return true
+		}
+	}
+	return false
+}

+ 27 - 60
lib/client.go → client/client.go

@@ -1,8 +1,7 @@
-package lib
+package client
 
 import (
-	"errors"
-	"fmt"
+	"github.com/cnlh/easyProxy/utils"
 	"log"
 	"net"
 	"sync"
@@ -28,54 +27,49 @@ func NewRPClient(svraddr string, tcpNum int, vKey string) *TRPClient {
 //start
 func (s *TRPClient) Start() error {
 	for i := 0; i < s.tcpNum; i++ {
-		go s.newConn()
+		go s.NewConn()
 	}
 	return nil
 }
 
 //新建
-func (s *TRPClient) newConn() error {
+func (s *TRPClient) NewConn() error {
 	s.Lock()
 	conn, err := net.Dial("tcp", s.svrAddr)
 	if err != nil {
 		log.Println("连接服务端失败,五秒后将重连")
 		time.Sleep(time.Second * 5)
 		s.Unlock()
-		go s.newConn()
+		go s.NewConn()
 		return err
 	}
 	s.Unlock()
-	return s.process(NewConn(conn))
+	return s.process(utils.NewConn(conn))
 }
 
 //处理
-func (s *TRPClient) process(c *Conn) error {
+func (s *TRPClient) process(c *utils.Conn) error {
 	c.SetAlive()
-	if _, err := c.Write([]byte(getverifyval(s.vKey))); err != nil {
+	if _, err := c.Write([]byte(utils.Getverifyval(s.vKey))); err != nil {
 		return err
 	}
-	c.wMain()
+	c.WriteMain()
 	for {
 		flags, err := c.ReadFlag()
 		if err != nil {
 			log.Println("服务端断开,五秒后将重连", err)
 			time.Sleep(5 * time.Second)
-			go s.newConn()
+			go s.NewConn()
 			break
 		}
 		switch flags {
-		case VERIFY_EER:
+		case utils.VERIFY_EER:
 			log.Fatalln("vkey:", s.vKey, "不正确,服务端拒绝连接,请检查")
-		case RES_SIGN: //代理请求模式
-			if err := s.dealHttp(c); err != nil {
-				log.Println(err)
-				return err
-			}
-		case WORK_CHAN: //隧道模式,每次开启10个,加快连接速度
+		case utils.WORK_CHAN: //隧道模式,每次开启10个,加快连接速度
 			for i := 0; i < 5; i++ {
 				go s.dealChan()
 			}
-		case RES_MSG:
+		case utils.RES_MSG:
 			log.Println("服务端返回错误。")
 		default:
 			log.Println("无法解析该错误。", flags)
@@ -94,15 +88,15 @@ func (s *TRPClient) dealChan() {
 		return
 	}
 	//验证
-	if _, err := conn.Write([]byte(getverifyval(s.vKey))); err != nil {
+	if _, err := conn.Write([]byte(utils.Getverifyval(s.vKey))); err != nil {
 		log.Println("connect to ", s.svrAddr, "error:", err)
 		return
 	}
 	//默认长连接保持
-	c := NewConn(conn)
+	c := utils.NewConn(conn)
 	c.SetAlive()
 	//写标志
-	c.wChan()
+	c.WriteChan()
 re:
 	//获取连接的host type(tcp or udp)
 	typeStr, host, en, de, crypt, mux, err := c.GetHostFromConn()
@@ -111,51 +105,24 @@ re:
 		c.Close()
 		return
 	}
-	//与目标建立连接,超时时间为3
-	server, err := net.DialTimeout(typeStr, host, time.Second*3)
-	if err != nil {
-		log.Println("connect to ", host, "error:", err, mux)
-		c.wFail()
-		goto end
-	}
-	c.wSuccess()
-	go relay(server, c.conn, de, crypt, mux)
-	relay(c.conn, server, en, crypt, mux)
-end:
+	Process(c, typeStr, host, en, de, crypt, mux)
 	if mux {
-		FlushConn(conn)
+		utils.FlushConn(conn)
 		goto re
 	} else {
 		c.Close()
 	}
 }
 
-//http模式处理
-func (s *TRPClient) dealHttp(c *Conn) error {
-	buf := make([]byte, 1024*32)
-	en, de, crypt, _ := c.GetConnInfoFromConn()
-	n, err := c.ReadFrom(buf, de, crypt)
-	if err != nil {
-		c.wError()
-		return err
-	}
-	req, err := DecodeRequest(buf[:n])
-	if err != nil {
-		c.wError()
-		return err
-	}
-	respBytes, err := GetEncodeResponse(req)
-	if err != nil {
-		c.wError()
-		return err
-	}
-	c.wSign()
-	n, err = c.WriteTo(respBytes, en, crypt)
+func Process(c *utils.Conn, typeStr, host string, en, de int, crypt, mux bool) {
+	//与目标建立连接,超时时间为3
+	server, err := net.DialTimeout(typeStr, host, time.Second*3)
 	if err != nil {
-		return err
-	}
-	if n != len(respBytes) {
-		return errors.New(fmt.Sprintf("发送数据长度错误,已经发送:%dbyte,总字节长:%dbyte\n", n, len(respBytes)))
+		log.Println("connect to ", host, "error:", err, mux)
+		c.WriteFail()
+		return
 	}
-	return nil
+	c.WriteSuccess()
+	go utils.Relay(server, c.Conn, de, crypt, mux)
+	utils.Relay(c.Conn, server, en, crypt, mux)
 }

+ 27 - 0
cmd/proxy_client.go

@@ -0,0 +1,27 @@
+package main
+
+import (
+	"flag"
+	"github.com/cnlh/easyProxy/client"
+	"log"
+	"strings"
+)
+
+var (
+	serverAddr = flag.String("server", "", "服务器地址ip:端口")
+	verifyKey  = flag.String("vkey", "", "验证密钥")
+)
+
+
+func main() {
+	flag.Parse()
+	//go func() {
+	//	http.ListenAndServe("0.0.0.0:8899", nil)
+	//}()
+	stop := make(chan int)
+	for _, v := range strings.Split(*verifyKey, ",") {
+		log.Println("客户端启动,连接:", *serverAddr, " 验证令牌:", v)
+		go client.NewRPClient(*serverAddr, 1, v).Start()
+	}
+	<-stop
+}

+ 47 - 0
cmd/proxy_server.go

@@ -0,0 +1,47 @@
+package main
+
+import (
+	"flag"
+	"github.com/cnlh/easyProxy/server"
+	"github.com/cnlh/easyProxy/utils"
+	_ "github.com/cnlh/easyProxy/web/routers"
+	"log"
+)
+
+var (
+	configPath   = flag.String("config", "config.json", "配置文件路径")
+	TcpPort      = flag.Int("tcpport", 8284, "客户端与服务端通信端口")
+	httpPort     = flag.Int("httpport", 8024, "对外监听的端口")
+	rpMode       = flag.String("mode", "client", "启动模式")
+	tunnelTarget = flag.String("target", "10.1.50.203:80", "远程目标")
+	VerifyKey    = flag.String("vkey", "", "验证密钥")
+	u            = flag.String("u", "", "验证用户名(socks5和web)")
+	p            = flag.String("p", "", "验证密码(socks5和web)")
+	compress     = flag.String("compress", "", "数据压缩方式(snappy)")
+	crypt        = flag.String("crypt", "false", "是否加密(true|false)")
+	mux          = flag.String("mux", "false", "是否TCP多路复用(true|false)")
+)
+
+func main() {
+	flag.Parse()
+	server.VerifyKey = *VerifyKey
+	log.Println("服务端启动,监听tcp服务端端口:", *TcpPort)
+	cnf := server.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,
+	}
+	cnf.CompressDecode, cnf.CompressEncode = utils.GetCompressType(cnf.Compress)
+	server.StartNewServer(*TcpPort, &cnf)
+}

+ 1 - 1
conf/app.conf

@@ -4,7 +4,7 @@ appname = easyProxy
 httpport = 8080
 
 #启动模式dev|pro
-runmode = pro
+runmode = dev
 
 #web管理密码
 password=123

+ 1 - 1
conf/hosts.csv

@@ -1,3 +1,3 @@
 b.proxy.com,127.0.0.1:82,o2430bnq22jgnmcl
 b.o.com,127.0.0.1:88,ts08z6vk5nc72fs8
-a.o.com,127.0.0.1:88,ts08z6vk5nc72fs8
+a.o.com,127.0.0.1:88,7n7bxc2bm1fyjfab

+ 3 - 1
conf/tasks.csv

@@ -1,3 +1,5 @@
 8001,tunnelServer,127.0.0.1:88,jq5i7n0sjs1h0jje,aaa,bbb,,1,0,0,0,1
-0,hostServer,,ts08z6vk5nc72fs8,aaac,bbb,snappy,1,0,1,2,3
 0,hostServer,,7n7bxc2bm1fyjfab,ab,b,,1,1,1,0,1
+0,hostServer,,ts08z6vk5nc72fs8,aaa,bbb,snappy,1,0,1,2,3
+8002,tunnelServer,127.0.0.1:88,2nxo93wvotb9g75s,,,,1,0,0,0,1
+8025,socks5Server,,2p3qs71oym3zx52w,,,,1,0,0,0,1

+ 0 - 228
lib/bridge.go

@@ -1,228 +0,0 @@
-package lib
-
-import (
-	"errors"
-	"log"
-	"net"
-	"sync"
-	"time"
-)
-
-type list struct {
-	connList chan *Conn
-}
-
-func (l *list) Add(c *Conn) {
-	l.connList <- c
-}
-
-func (l *list) Pop() *Conn {
-	return <-l.connList
-}
-func (l *list) Len() int {
-	return len(l.connList)
-}
-
-func newList() *list {
-	l := new(list)
-	l.connList = make(chan *Conn, 1000)
-	return l
-}
-
-type Tunnel struct {
-	tunnelPort int              //通信隧道端口
-	listener   *net.TCPListener //server端监听
-	signalList map[string]*list //通信
-	tunnelList map[string]*list //隧道
-	lock       sync.Mutex
-	tunnelLock sync.Mutex
-}
-
-func newTunnel(tunnelPort int) *Tunnel {
-	t := new(Tunnel)
-	t.tunnelPort = tunnelPort
-	t.signalList = make(map[string]*list)
-	t.tunnelList = make(map[string]*list)
-	return t
-}
-
-func (s *Tunnel) StartTunnel() error {
-	var err error
-	s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.tunnelPort, ""})
-	if err != nil {
-		return err
-	}
-	go s.tunnelProcess()
-	return nil
-}
-
-//tcp server
-func (s *Tunnel) tunnelProcess() error {
-	var err error
-	for {
-		conn, err := s.listener.Accept()
-		if err != nil {
-			log.Println(err)
-			continue
-		}
-		go s.cliProcess(NewConn(conn))
-	}
-	return err
-}
-
-//验证失败,返回错误验证flag,并且关闭连接
-func (s *Tunnel) verifyError(c *Conn) {
-	c.conn.Write([]byte(VERIFY_EER))
-	c.conn.Close()
-}
-
-func (s *Tunnel) cliProcess(c *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 {
-		log.Println("客户端读超时。客户端地址为::", c.conn.RemoteAddr())
-		c.conn.Close()
-		return err
-	}
-	if !verify(string(vval)) {
-		log.Println("当前客户端连接校验错误,关闭此客户端:", c.conn.RemoteAddr())
-		s.verifyError(c)
-		return err
-	}
-	c.conn.(*net.TCPConn).SetReadDeadline(time.Time{})
-	//做一个判断 添加到对应的channel里面以供使用
-	if flag, err := c.ReadFlag(); err != nil {
-		return err
-	} else {
-		return s.typeDeal(flag, c, string(vval))
-	}
-}
-
-//tcp连接类型区分
-func (s *Tunnel) typeDeal(typeVal string, c *Conn, cFlag string) error {
-	switch typeVal {
-	case WORK_MAIN:
-		s.addList(s.signalList, c, cFlag)
-	case WORK_CHAN:
-		s.addList(s.tunnelList, c, cFlag)
-	default:
-		return errors.New("无法识别")
-	}
-	c.SetAlive()
-	return nil
-}
-
-//加到对应的list中
-func (s *Tunnel) addList(m map[string]*list, c *Conn, cFlag string) {
-	s.lock.Lock()
-	if v, ok := m[cFlag]; ok {
-		v.Add(c)
-	} else {
-		l := newList()
-		l.Add(c)
-		m[cFlag] = l
-	}
-	s.lock.Unlock()
-}
-
-//新建隧道
-func (s *Tunnel) newChan(cFlag string) error {
-	if err := s.wait(s.signalList, cFlag); err != nil {
-		return err
-	}
-retry:
-	connPass := s.signalList[cFlag].Pop()
-	_, err := connPass.conn.Write([]byte("chan"))
-	if err != nil {
-		log.Println(err)
-		goto retry
-	}
-	s.signalList[cFlag].Add(connPass)
-	return nil
-}
-
-//得到一个tcp隧道
-func (s *Tunnel) GetTunnel(cFlag string, en, de int, crypt, mux bool) (c *Conn, err error) {
-	s.tunnelLock.Lock()
-	if v, ok := s.tunnelList[cFlag]; !ok || v.Len() < 3 { //新建通道
-		go s.newChan(cFlag)
-	}
-retry:
-	if err = s.wait(s.tunnelList, cFlag); err != nil {
-		return
-	}
-	c = s.tunnelList[cFlag].Pop()
-	if _, err = c.wTest(); err != nil {
-		c.Close()
-		goto retry
-	}
-	c.WriteConnInfo(en, de, crypt, mux)
-	s.tunnelLock.Unlock()
-	return
-}
-
-//得到一个通信通道
-func (s *Tunnel) GetSignal(cFlag string) (err error, conn *Conn) {
-	if v, ok := s.signalList[cFlag]; !ok || v.Len() == 0 {
-		err = errors.New("客户端未连接")
-		return
-	}
-	conn = s.signalList[cFlag].Pop()
-	return
-}
-
-//重回slice 复用
-func (s *Tunnel) ReturnSignal(conn *Conn, cFlag string) {
-	if v, ok := s.signalList[cFlag]; ok {
-		v.Add(conn)
-	}
-}
-
-//重回slice 复用
-func (s *Tunnel) ReturnTunnel(conn *Conn, cFlag string) {
-	if v, ok := s.tunnelList[cFlag]; ok {
-		FlushConn(conn.conn)
-		v.Add(conn)
-	}
-}
-
-//删除通信通道
-func (s *Tunnel) DelClientSignal(cFlag string) {
-	s.delClient(cFlag, s.signalList)
-}
-
-//删除隧道
-func (s *Tunnel) DelClientTunnel(cFlag string) {
-	s.delClient(cFlag, s.tunnelList)
-}
-
-func (s *Tunnel) delClient(cFlag string, l map[string]*list) {
-	if t := l[getverifyval(cFlag)]; t != nil {
-		for {
-			if t.Len() <= 0 {
-				break
-			}
-			t.Pop().Close()
-		}
-		delete(l, getverifyval(cFlag))
-	}
-}
-
-//等待
-func (s *Tunnel) wait(m map[string]*list, cFlag string) error {
-	ticker := time.NewTicker(time.Millisecond * 100)
-	stop := time.After(time.Second * 10)
-loop:
-	for {
-		select {
-		case <-ticker.C:
-			if _, ok := m[cFlag]; ok {
-				ticker.Stop()
-				break loop
-			}
-		case <-stop:
-			return errors.New("client key: " + cFlag + ",err: get client conn timeout")
-		}
-	}
-	return nil
-}

+ 0 - 201
lib/init.go

@@ -1,201 +0,0 @@
-package lib
-
-import (
-	"errors"
-	"flag"
-	"log"
-	"net/http"
-	_ "net/http/pprof"
-	"reflect"
-	"strings"
-	"sync"
-)
-
-var (
-	configPath   = flag.String("config", "config.json", "配置文件路径")
-	TcpPort      = flag.Int("tcpport", 8284, "客户端与服务端通信端口")
-	httpPort     = flag.Int("httpport", 8024, "对外监听的端口")
-	rpMode       = flag.String("mode", "client", "启动模式")
-	tunnelTarget = flag.String("target", "10.1.50.203:80", "远程目标")
-	verifyKey    = flag.String("vkey", "", "验证密钥")
-	u            = flag.String("u", "", "验证用户名(socks5和web)")
-	p            = flag.String("p", "", "验证密码(socks5和web)")
-	compress     = flag.String("compress", "", "数据压缩方式(snappy)")
-	serverAddr   = flag.String("server", "", "服务器地址ip:端口")
-	crypt        = flag.String("crypt", "false", "是否加密(true|false)")
-	mux          = flag.String("mux", "false", "是否TCP多路复用(true|false)")
-	config       Config
-	err          error
-	RunList      map[string]interface{} //运行中的任务
-	bridge       *Tunnel
-	CsvDb        *Csv
-)
-
-const cryptKey = "1234567812345678"
-
-func init() {
-	RunList = make(map[string]interface{})
-}
-
-func InitClient() {
-	flag.Parse()
-	if *rpMode == "client" {
-		go func() {
-			http.ListenAndServe("0.0.0.0:8899", nil)
-		}()
-		JsonParse := NewJsonStruct()
-		if config, err = JsonParse.Load(*configPath); err != nil {
-			log.Println("配置文件加载失败")
-		}
-		stop := make(chan int)
-		for _, v := range strings.Split(*verifyKey, ",") {
-			log.Println("客户端启动,连接:", *serverAddr, " 验证令牌:", v)
-			go NewRPClient(*serverAddr, 1, v).Start()
-		}
-		<-stop
-	}
-}
-func InitMode() {
-	flag.Parse()
-	if *rpMode == "client" {
-		go func() {
-			http.ListenAndServe("0.0.0.0:8899", nil)
-		}()
-		JsonParse := NewJsonStruct()
-		if config, err = JsonParse.Load(*configPath); err != nil {
-			log.Println("配置文件加载失败")
-		}
-		stop := make(chan int)
-		for _, v := range strings.Split(*verifyKey, ",") {
-			log.Println("客户端启动,连接:", *serverAddr, " 验证令牌:", v)
-			go NewRPClient(*serverAddr, 1, v).Start()
-		}
-		<-stop
-	} else {
-		bridge = newTunnel(*TcpPort)
-		if err := bridge.StartTunnel(); err != nil {
-			log.Fatalln("服务端开启失败", err)
-		}
-		log.Println("服务端启动,监听tcp服务端端口:", *TcpPort)
-		cnf := ServerConfig{
-			TcpPort:        *httpPort,
-			Mode:           *rpMode,
-			Target:         *tunnelTarget,
-			VerifyKey:      *verifyKey,
-			U:              *u,
-			P:              *p,
-			Compress:       *compress,
-			Start:          0,
-			IsRun:          0,
-			ClientStatus:   0,
-			Crypt:          GetBoolByStr(*crypt),
-			Mux:            GetBoolByStr(*mux),
-			CompressEncode: 0,
-			CompressDecode: 0,
-		}
-		cnf.CompressDecode, cnf.CompressEncode = getCompressType(cnf.Compress)
-		if svr := newMode(bridge, &cnf);
-			svr != nil {
-			reflect.ValueOf(svr).MethodByName("Start").Call(nil)
-		} else {
-			log.Fatalln("启动模式不正确")
-		}
-	}
-}
-
-//从csv文件中恢复任务
-func InitFromCsv() {
-	for _, v := range CsvDb.Tasks {
-		if v.Start == 1 {
-			log.Println(""+
-				"启动模式:", v.Mode, "监听端口:", v.TcpPort, "客户端令牌:", v.VerifyKey)
-			AddTask(v)
-		}
-	}
-}
-
-func newMode(bridge *Tunnel, config *ServerConfig) interface{} {
-	switch config.Mode {
-	case "httpServer":
-		return NewHttpModeServer(bridge, config)
-	case "tunnelServer":
-		return NewTunnelModeServer(ProcessTunnel, bridge, config)
-	case "socks5Server":
-		return NewSock5ModeServer(bridge, config)
-	case "httpProxyServer":
-		return NewTunnelModeServer(ProcessHttp, bridge, config)
-	case "udpServer":
-		return NewUdpModeServer(bridge, config)
-	case "webServer":
-		InitCsvDb()
-		return NewWebServer(bridge)
-	case "hostServer":
-		return NewHostServer(config)
-	case "httpHostServer":
-		return NewTunnelModeServer(ProcessHost, bridge, config)
-	}
-	return nil
-}
-
-func StopServer(cFlag string) error {
-	if v, ok := RunList[cFlag]; ok {
-		reflect.ValueOf(v).MethodByName("Close").Call(nil)
-		delete(RunList, cFlag)
-		if *verifyKey == "" { //多客户端模式关闭相关隧道
-			bridge.DelClientSignal(cFlag)
-			bridge.DelClientTunnel(cFlag)
-		}
-		if t, err := CsvDb.GetTask(cFlag); err != nil {
-			return err
-		} else {
-			t.Start = 0
-			CsvDb.UpdateTask(t)
-		}
-		return nil
-	}
-	return errors.New("未在运行中")
-}
-
-func AddTask(t *ServerConfig) error {
-	t.CompressDecode, t.CompressEncode = getCompressType(t.Compress)
-	if svr := newMode(bridge, t); svr != nil {
-		RunList[t.VerifyKey] = svr
-		go func() {
-			err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
-			if err.Interface() != nil {
-				log.Println("客户端", t.VerifyKey, "启动失败,错误:", err)
-				delete(RunList, t.VerifyKey)
-			}
-		}()
-	} else {
-		return errors.New("启动模式不正确")
-	}
-	return nil
-}
-
-func StartTask(vKey string) error {
-	if t, err := CsvDb.GetTask(vKey); err != nil {
-		return err
-	} else {
-		AddTask(t)
-		t.Start = 1
-		CsvDb.UpdateTask(t)
-	}
-	return nil
-}
-
-func DelTask(vKey string) error {
-	if err := StopServer(vKey); err != nil {
-		return err
-	}
-	return CsvDb.DelTask(vKey)
-}
-
-func InitCsvDb() *Csv {
-	var once sync.Once
-	once.Do(func() {
-		CsvDb = NewCsv( bridge, RunList)
-		CsvDb.Init()
-	})
-	return CsvDb
-}

+ 0 - 326
lib/tcp.go

@@ -1,326 +0,0 @@
-package lib
-
-import (
-	"errors"
-	"fmt"
-	"github.com/astaxie/beego"
-	"github.com/astaxie/beego/session"
-	"io/ioutil"
-	"log"
-	"net"
-	"net/http"
-	"strings"
-)
-
-var GlobalHostSessions *session.Manager
-
-const (
-	VERIFY_EER         = "vkey"
-	WORK_MAIN          = "main"
-	WORK_CHAN          = "chan"
-	RES_SIGN           = "sign"
-	RES_MSG            = "msg0"
-	CONN_SUCCESS       = "sucs"
-	CONN_ERROR         = "fail"
-	TEST_FLAG          = "tst"
-	CONN_TCP           = "tcp"
-	CONN_UDP           = "udp"
-	Unauthorized_BYTES = `HTTP/1.1 401 Unauthorized
-Content-Type: text/plain; charset=utf-8
-WWW-Authenticate: Basic realm="easyProxy"
-
-401 Unauthorized`
-)
-
-type process func(c *Conn, s *TunnelModeServer) error
-
-type HttpModeServer struct {
-	bridge *Tunnel
-	config *ServerConfig
-}
-
-//http
-func NewHttpModeServer(bridge *Tunnel, cnf *ServerConfig) *HttpModeServer {
-	s := new(HttpModeServer)
-	s.bridge = bridge
-	s.config = cnf
-	return s
-}
-
-//开始
-func (s *HttpModeServer) Start() {
-	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
-	retry:
-		u := beego.AppConfig.String("basic.user")
-		p := beego.AppConfig.String("basic.password")
-		if u != "" && p != "" && !checkAuth(r, u, p) {
-			w.Header().Set("WWW-Authenticate", `Basic realm="easyProxy""`)
-			w.WriteHeader(401)
-			w.Write([]byte("401 Unauthorized\n"))
-			return
-		}
-		err, conn := s.bridge.GetSignal(getverifyval(s.config.VerifyKey))
-		if err != nil {
-			BadRequest(w)
-			return
-		}
-		if err := s.writeRequest(r, conn); err != nil {
-			log.Println("write request to client error:", err)
-			conn.Close()
-			goto retry
-			return
-		}
-		err = s.writeResponse(w, conn)
-		if err != nil {
-			log.Println("write response error:", err)
-			conn.Close()
-			goto retry
-			return
-		}
-		s.bridge.ReturnSignal(conn, getverifyval(s.config.VerifyKey))
-	})
-	log.Fatalln(http.ListenAndServe(fmt.Sprintf(":%d", s.config.TcpPort), nil))
-}
-
-//req转为bytes发送给client端
-func (s *HttpModeServer) writeRequest(r *http.Request, conn *Conn) error {
-	raw, err := EncodeRequest(r)
-	if err != nil {
-		return err
-	}
-	conn.wSign()
-	conn.WriteConnInfo(s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
-	c, err := conn.WriteTo(raw, s.config.CompressEncode, s.config.Crypt)
-	if err != nil {
-		return err
-	}
-	if c != len(raw) {
-		return errors.New("写出长度与字节长度不一致。")
-	}
-	return nil
-}
-
-//从client读取出Response
-func (s *HttpModeServer) writeResponse(w http.ResponseWriter, c *Conn) error {
-	flags, err := c.ReadFlag()
-	if err != nil {
-		return err
-	}
-	switch flags {
-	case RES_SIGN:
-		buf := make([]byte, 1024*1024*32)
-		n, err := c.ReadFrom(buf, s.config.CompressDecode, s.config.Crypt)
-		if err != nil {
-			return err
-		}
-		resp, err := DecodeResponse(buf[:n])
-		if err != nil {
-			return err
-		}
-		bodyBytes, err := ioutil.ReadAll(resp.Body)
-		if err != nil {
-			return err
-		}
-		for k, v := range resp.Header {
-			for _, v2 := range v {
-				w.Header().Set(k, v2)
-			}
-		}
-		w.WriteHeader(resp.StatusCode)
-		w.Write(bodyBytes)
-	case RES_MSG:
-		BadRequest(w)
-		return errors.New("客户端请求出错")
-	default:
-		BadRequest(w)
-		return errors.New("无法解析此错误")
-	}
-	return nil
-}
-
-type TunnelModeServer struct {
-	process  process
-	bridge   *Tunnel
-	config   *ServerConfig
-	listener *net.TCPListener
-}
-
-//tcp|http|host
-func NewTunnelModeServer(process process, bridge *Tunnel, cnf *ServerConfig) *TunnelModeServer {
-	s := new(TunnelModeServer)
-	s.bridge = bridge
-	s.process = process
-	s.config = cnf
-	return s
-}
-
-//开始
-func (s *TunnelModeServer) Start() error {
-	s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.config.TcpPort, ""})
-	if err != nil {
-		return err
-	}
-	for {
-		conn, err := s.listener.AcceptTCP()
-		if err != nil {
-			if strings.Contains(err.Error(), "use of closed network connection") {
-				break
-			}
-			log.Println(err)
-			continue
-		}
-		go s.process(NewConn(conn), s)
-	}
-	return nil
-}
-
-//权限认证
-func (s *TunnelModeServer) auth(r *http.Request, c *Conn, u, p string) error {
-	if u != "" && p != "" && !checkAuth(r, u, p) {
-		c.Write([]byte(Unauthorized_BYTES))
-		c.Close()
-		return errors.New("401 Unauthorized")
-	}
-	return nil
-}
-
-//与客户端建立通道
-func (s *TunnelModeServer) dealClient(c *Conn, cnf *ServerConfig, addr string, method string, rb []byte) error {
-	link, err := s.bridge.GetTunnel(getverifyval(cnf.VerifyKey), cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, cnf.Mux)
-	defer func() {
-		if cnf.Mux {
-			s.bridge.ReturnTunnel(link, getverifyval(cnf.VerifyKey))
-		} else {
-			c.Close()
-		}
-	}()
-	if err != nil {
-		log.Println(err)
-		c.Close()
-		return err
-	}
-	if _, err := link.WriteHost(CONN_TCP, addr); err != nil {
-		c.Close()
-		link.Close()
-		log.Println(err)
-		return err
-	}
-	if flag, err := link.ReadFlag(); err == nil {
-		if flag == CONN_SUCCESS {
-			if method == "CONNECT" {
-				fmt.Fprint(c, "HTTP/1.1 200 Connection established\r\n")
-			} else {
-				link.WriteTo(rb, cnf.CompressEncode, cnf.Crypt)
-			}
-			go relay(link.conn, c.conn, cnf.CompressEncode, cnf.Crypt, cnf.Mux)
-			relay(c.conn, link.conn, cnf.CompressDecode, cnf.Crypt, cnf.Mux)
-		}
-	}
-	return nil
-}
-
-//close
-func (s *TunnelModeServer) Close() error {
-	return s.listener.Close()
-}
-
-//tcp隧道模式
-func ProcessTunnel(c *Conn, s *TunnelModeServer) error {
-	method, _, 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, method, rb)
-}
-
-//http代理模式
-func ProcessHttp(c *Conn, s *TunnelModeServer) error {
-	method, addr, rb, err, r := c.GetHost()
-	if err != nil {
-		c.Close()
-		return err
-	}
-	if err := s.auth(r, c, s.config.U, s.config.P); err != nil {
-		return err
-	}
-	//TODO效率问题
-	return s.dealClient(c, s.config, addr, method, rb)
-}
-
-//多客户端域名代理
-func ProcessHost(c *Conn, s *TunnelModeServer) error {
-	method, addr, rb, err, r := c.GetHost()
-	if err != nil {
-		c.Close()
-		return err
-	}
-	host, task, err := getKeyByHost(addr)
-	if err := s.auth(r, c, task.U, task.P); err != nil {
-		return err
-	}
-	if err != nil {
-		c.Close()
-		return err
-	}
-	return s.dealClient(c, task, host.Target, method, rb)
-}
-
-//web管理方式
-type WebServer struct {
-	bridge *Tunnel
-}
-
-//开始
-func (s *WebServer) Start() {
-	InitFromCsv()
-	p, _ := beego.AppConfig.Int("hostPort")
-	t := &ServerConfig{
-		TcpPort:      p,
-		Mode:         "httpHostServer",
-		Target:       "",
-		VerifyKey:    "",
-		U:            "",
-		P:            "",
-		Compress:     "",
-		Start:        1,
-		IsRun:        0,
-		ClientStatus: 0,
-	}
-	AddTask(t)
-	beego.BConfig.WebConfig.Session.SessionOn = true
-	log.Println("web管理启动,访问端口为", beego.AppConfig.String("httpport"))
-	beego.SetViewsPath(beego.AppPath + "/views/")
-	beego.SetStaticPath("/static/", beego.AppPath+"/static/")
-	beego.Run()
-}
-
-//new
-func NewWebServer(bridge *Tunnel) *WebServer {
-	s := new(WebServer)
-	s.bridge = bridge
-	return s
-}
-
-//host
-type HostServer struct {
-	config *ServerConfig
-}
-
-//开始
-func (s *HostServer) Start() error {
-	return nil
-}
-
-//TODO:host模式的客户端,无需指定和监听端口等
-func NewHostServer(cnf *ServerConfig) *HostServer {
-	s := new(HostServer)
-	s.config = cnf
-	return s
-}
-
-//close
-func (s *HostServer) Close() error {
-	return nil
-}

+ 0 - 330
lib/util.go

@@ -1,330 +0,0 @@
-package lib
-
-import (
-	"bufio"
-	"bytes"
-	"encoding/base64"
-	"encoding/binary"
-	"errors"
-	"fmt"
-	"io"
-	"log"
-	"net"
-	"net/http"
-	"net/http/httputil"
-	"net/url"
-	"regexp"
-	"strconv"
-	"strings"
-	"sync"
-	"time"
-)
-
-var (
-	disabledRedirect = errors.New("disabled redirect.")
-)
-
-const (
-	COMPRESS_NONE_ENCODE = iota
-	COMPRESS_NONE_DECODE
-	COMPRESS_SNAPY_ENCODE
-	COMPRESS_SNAPY_DECODE
-	IO_EOF = "PROXYEOF"
-)
-
-//error
-func BadRequest(w http.ResponseWriter) {
-	http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
-}
-
-//发送请求并转为bytes
-func GetEncodeResponse(req *http.Request) ([]byte, error) {
-	var respBytes []byte
-	client := new(http.Client)
-	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
-		return disabledRedirect
-	}
-	resp, err := client.Do(req)
-	disRedirect := err != nil && strings.Contains(err.Error(), disabledRedirect.Error())
-	if err != nil && !disRedirect {
-		return respBytes, err
-	}
-	if !disRedirect {
-		defer resp.Body.Close()
-	} else {
-		resp.Body = nil
-		resp.ContentLength = 0
-	}
-	respBytes, err = EncodeResponse(resp)
-	return respBytes, nil
-}
-
-// 将request转为bytes
-func EncodeRequest(r *http.Request) ([]byte, error) {
-	raw := bytes.NewBuffer([]byte{})
-	reqBytes, err := httputil.DumpRequest(r, true)
-	if err != nil {
-		return nil, err
-	}
-	binary.Write(raw, binary.LittleEndian, bool(r.URL.Scheme == "https"))
-	binary.Write(raw, binary.LittleEndian, reqBytes)
-	return raw.Bytes(), nil
-}
-
-// 将字节转为request
-func DecodeRequest(data []byte) (*http.Request, error) {
-	req, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(data[1:])))
-	if err != nil {
-		return nil, err
-	}
-	str := strings.Split(req.Host, ":")
-	req.Host, err = getHost(str[0])
-	if err != nil {
-		return nil, err
-	}
-	scheme := "http"
-	if data[0] == 1 {
-		scheme = "https"
-	}
-	req.URL, _ = url.Parse(fmt.Sprintf("%s://%s%s", scheme, req.Host, req.RequestURI))
-	req.RequestURI = ""
-	return req, nil
-}
-
-// 将response转为字节
-func EncodeResponse(r *http.Response) ([]byte, error) {
-	respBytes, err := httputil.DumpResponse(r, true)
-	if err != nil {
-		return nil, err
-	}
-	if config.Replace == 1 {
-		respBytes = replaceHost(respBytes)
-	}
-	return respBytes, nil
-}
-
-// 将字节转为response
-func DecodeResponse(data []byte) (*http.Response, error) {
-	resp, err := http.ReadResponse(bufio.NewReader(bytes.NewReader(data)), nil)
-	if err != nil {
-		return nil, err
-	}
-	return resp, nil
-}
-
-// 根据host地址从配置是文件中查找对应目标
-func getHost(str string) (string, error) {
-	for _, v := range config.SiteList {
-		if v.Host == str {
-			return v.Url + ":" + strconv.Itoa(v.Port), nil
-		}
-	}
-	return "", errors.New("没有找到解析的的host!")
-}
-
-//替换
-func replaceHost(resp []byte) []byte {
-	str := string(resp)
-	for _, v := range config.SiteList {
-		str = strings.Replace(str, v.Url+":"+strconv.Itoa(v.Port), v.Host, -1)
-		str = strings.Replace(str, v.Url, v.Host, -1)
-	}
-	return []byte(str)
-}
-
-//copy
-func relay(in, out net.Conn, compressType int, crypt, mux bool) {
-	switch compressType {
-	case COMPRESS_SNAPY_ENCODE:
-		copyBuffer(NewSnappyConn(in, crypt), out)
-		if mux {
-			out.Close()
-			NewSnappyConn(in, crypt).Write([]byte(IO_EOF))
-		}
-	case COMPRESS_SNAPY_DECODE:
-		copyBuffer(in, NewSnappyConn(out, crypt))
-		if mux {
-			in.Close()
-		}
-	case COMPRESS_NONE_ENCODE:
-		copyBuffer(NewCryptConn(in, crypt), out)
-		if mux {
-			out.Close()
-			NewCryptConn(in, crypt).Write([]byte(IO_EOF))
-		}
-	case COMPRESS_NONE_DECODE:
-		copyBuffer(in, NewCryptConn(out, crypt))
-		if mux {
-			in.Close()
-		}
-	}
-	if !mux {
-		in.Close()
-		out.Close()
-	}
-}
-
-//判断压缩方式
-func getCompressType(compress string) (int, int) {
-	switch compress {
-	case "":
-		return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE
-	case "snappy":
-		return COMPRESS_SNAPY_DECODE, COMPRESS_SNAPY_ENCODE
-	default:
-		log.Fatalln("数据压缩格式错误")
-	}
-	return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE
-}
-
-//简单的一个校验值
-func getverifyval(vkey string) string {
-	//单客户端模式
-	if *verifyKey != "" {
-		return Md5(*verifyKey)
-	}
-	return Md5(vkey)
-}
-
-//验证
-func verify(verifyKeyMd5 string) bool {
-	if *verifyKey != "" && getverifyval(*verifyKey) == verifyKeyMd5 {
-		return true
-	}
-	if *verifyKey == "" {
-		for k := range RunList {
-			if getverifyval(k) == verifyKeyMd5 {
-				return true
-			}
-		}
-	}
-	return false
-}
-
-//get key by host from x
-func getKeyByHost(host string) (h *HostList, t *ServerConfig, err error) {
-	for _, v := range CsvDb.Hosts {
-		if strings.Contains(host, v.Host) {
-			h = v
-			t, err = CsvDb.GetTask(v.Vkey)
-			return
-		}
-	}
-	err = errors.New("未找到host对应的内网目标")
-	return
-}
-
-//通过host获取对应的ip地址
-func Gethostbyname(hostname string) string {
-	if !DomainCheck(hostname) {
-		return hostname
-	}
-	ips, _ := net.LookupIP(hostname)
-	if ips != nil {
-		for _, v := range ips {
-			if v.To4() != nil {
-				return v.String()
-			}
-		}
-	}
-	return ""
-}
-
-//检查是否是域名
-func DomainCheck(domain string) bool {
-	var match bool
-	IsLine := "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}(/)"
-	NotLine := "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}"
-	match, _ = regexp.MatchString(IsLine, domain)
-	if !match {
-		match, _ = regexp.MatchString(NotLine, domain)
-	}
-	return match
-}
-
-//检查basic认证
-func checkAuth(r *http.Request, user, passwd string) bool {
-	s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
-	if len(s) != 2 {
-		return false
-	}
-
-	b, err := base64.StdEncoding.DecodeString(s[1])
-	if err != nil {
-		return false
-	}
-
-	pair := strings.SplitN(string(b), ":", 2)
-	if len(pair) != 2 {
-		return false
-	}
-	return pair[0] == user && pair[1] == passwd
-}
-
-//get bool by str
-func GetBoolByStr(s string) bool {
-	switch s {
-	case "1", "true":
-		return true
-	}
-	return false
-}
-
-//get str by bool
-func GetStrByBool(b bool) string {
-	if b {
-		return "1"
-	}
-	return "0"
-}
-func GetIntNoerrByStr(str string) int {
-	i, _ := strconv.Atoi(str)
-	return i
-}
-
-var bufPool = sync.Pool{
-	New: func() interface{} {
-		return make([]byte, 65535)
-	},
-}
-// io.copy的优化版,读取buffer长度原为32*1024,与snappy不同,导致读取出的内容存在差异,不利于解密,特此修改
-func copyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
-	//TODO 回收问题
-	buf := bufPool.Get().([]byte)
-	for {
-		nr, er := src.Read(buf)
-		if nr > 0 {
-			nw, ew := dst.Write(buf[0:nr])
-			if nw > 0 {
-				written += int64(nw)
-			}
-			if ew != nil {
-				err = ew
-				break
-			}
-			if nr != nw {
-				err = io.ErrShortWrite
-				break
-			}
-		}
-		if er != nil {
-			if er != io.EOF {
-				err = er
-			}
-			break
-		}
-	}
-	return written, err
-}
-
-//连接重置 清空缓存区
-func FlushConn(c net.Conn) {
-	c.SetReadDeadline(time.Now().Add(time.Second * 3))
-	buf := bufPool.Get().([]byte)
-	for {
-		if _, err := c.Read(buf); err != nil {
-			break
-		}
-	}
-	c.SetReadDeadline(time.Time{})
-}

+ 0 - 10
main.go

@@ -1,10 +0,0 @@
-package main
-
-import (
-	"github.com/cnlh/easyProxy/lib"
-	_ "github.com/cnlh/easyProxy/routers"
-)
-
-func main() {
-	lib.InitMode()
-}

+ 10 - 74
lib/file.go → server/file.go

@@ -1,11 +1,10 @@
-package lib
+package server
 
 import (
 	"encoding/csv"
-	"encoding/json"
 	"errors"
 	"github.com/astaxie/beego"
-	"io/ioutil"
+	"github.com/cnlh/easyProxy/utils"
 	"log"
 	"os"
 	"strconv"
@@ -34,9 +33,8 @@ type HostList struct {
 	Target string //目标
 }
 
-func NewCsv(bridge *Tunnel, runList map[string]interface{}) *Csv {
+func NewCsv(runList map[string]interface{}) *Csv {
 	c := new(Csv)
-	c.Bridge = bridge
 	c.RunList = runList
 	return c
 }
@@ -44,7 +42,6 @@ func NewCsv(bridge *Tunnel, runList map[string]interface{}) *Csv {
 type Csv struct {
 	Tasks   []*ServerConfig
 	Path    string
-	Bridge  *Tunnel
 	RunList map[string]interface{}
 	Hosts   []*HostList //域名列表
 }
@@ -72,8 +69,8 @@ func (s *Csv) StoreTasksToCsv() {
 			task.P,
 			task.Compress,
 			strconv.Itoa(task.Start),
-			GetStrByBool(task.Crypt),
-			GetStrByBool(task.Mux),
+			utils.GetStrByBool(task.Crypt),
+			utils.GetStrByBool(task.Mux),
 			strconv.Itoa(task.CompressEncode),
 			strconv.Itoa(task.CompressDecode),
 		}
@@ -118,10 +115,10 @@ func (s *Csv) LoadTaskFromCsv() {
 			P:              item[5],
 			Compress:       item[6],
 			Start:          Start,
-			Crypt:          GetBoolByStr(item[8]),
-			Mux:            GetBoolByStr(item[9]),
-			CompressEncode: GetIntNoerrByStr(item[10]),
-			CompressDecode: GetIntNoerrByStr(item[11]),
+			Crypt:          utils.GetBoolByStr(item[8]),
+			Mux:            utils.GetBoolByStr(item[9]),
+			CompressEncode: utils.GetIntNoerrByStr(item[10]),
+			CompressDecode: utils.GetIntNoerrByStr(item[11]),
 		}
 		tasks = append(tasks, post)
 	}
@@ -130,7 +127,7 @@ func (s *Csv) LoadTaskFromCsv() {
 
 func (s *Csv) StoreHostToCsv() {
 	// 创建文件
-	csvFile, err := os.Create(s.Path + "hosts.csv")
+	csvFile, err := os.Create(beego.AppPath + "/conf/hosts.csv")
 	if err != nil {
 		panic(err)
 	}
@@ -186,38 +183,6 @@ func (s *Csv) LoadHostFromCsv() {
 	s.Hosts = hosts
 }
 
-func (s *Csv) GetServerConfig(start, length int, typeVal string) ([]*ServerConfig, int) {
-	list := make([]*ServerConfig, 0)
-	var cnt int
-	for _, v := range s.Tasks {
-		if v.Mode != typeVal {
-			continue
-		}
-		cnt++
-		if start--; start < 0 {
-			if length--; length > 0 {
-				if _, ok := s.RunList[v.VerifyKey]; ok {
-					v.IsRun = 1
-				} else {
-					v.IsRun = 0
-				}
-				if s, ok := s.Bridge.signalList[getverifyval(v.VerifyKey)]; ok {
-					if s.Len() > 0 {
-						v.ClientStatus = 1
-					} else {
-						v.ClientStatus = 0
-					}
-				} else {
-					v.ClientStatus = 0
-				}
-				list = append(list, v)
-			}
-		}
-
-	}
-	return list, cnt
-}
-
 func (s *Csv) NewTask(t *ServerConfig) {
 	s.Tasks = append(s.Tasks, t)
 	s.StoreTasksToCsv()
@@ -232,7 +197,6 @@ func (s *Csv) UpdateTask(t *ServerConfig) error {
 			return nil
 		}
 	}
-	//TODO:待测试
 	return errors.New("不存在")
 }
 
@@ -297,31 +261,3 @@ func (s *Csv) GetHostList(start, length int, vKey string) ([]*HostList, int) {
 	}
 	return list, cnt
 }
-
-type Site struct {
-	Host string
-	Url  string
-	Port int
-}
-type Config struct {
-	SiteList []Site
-	Replace  int
-}
-type JsonStruct struct {
-}
-
-func NewJsonStruct() *JsonStruct {
-	return &JsonStruct{}
-}
-func (jst *JsonStruct) Load(filename string) (Config, error) {
-	data, err := ioutil.ReadFile(filename)
-	config := Config{}
-	if err != nil {
-		return config, errors.New("配置文件打开错误")
-	}
-	err = json.Unmarshal(data, &config)
-	if err != nil {
-		return config, errors.New("配置文件解析错误")
-	}
-	return config, nil
-}

+ 209 - 0
server/server.go

@@ -0,0 +1,209 @@
+package server
+
+import (
+	"errors"
+	"github.com/cnlh/easyProxy/bridge"
+	"github.com/cnlh/easyProxy/utils"
+	"log"
+	"reflect"
+	"strings"
+	"sync"
+)
+
+var (
+	Bridge    *bridge.Tunnel
+	RunList   map[string]interface{} //运行中的任务
+	CsvDb     *Csv
+	VerifyKey string
+)
+
+func init() {
+	RunList = make(map[string]interface{})
+}
+
+//从csv文件中恢复任务
+func InitFromCsv() {
+	for _, v := range CsvDb.Tasks {
+		if v.Start == 1 {
+			log.Println("启动模式:", v.Mode, "监听端口:", v.TcpPort, "客户端令牌:", v.VerifyKey)
+			AddTask(v)
+		}
+	}
+}
+
+//start a new server
+func StartNewServer(bridgePort int, cnf *ServerConfig) {
+	Bridge = bridge.NewTunnel(bridgePort, RunList)
+	if err := Bridge.StartTunnel(); err != nil {
+		log.Fatalln("服务端开启失败", err)
+	}
+	if svr := NewMode(Bridge, cnf); svr != nil {
+		RunList[cnf.VerifyKey] = svr
+		err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
+		if err.Interface() != nil {
+			log.Println(err)
+		}
+	} else {
+		log.Fatalln("启动模式不正确")
+	}
+}
+
+//new a server by mode name
+func NewMode(Bridge *bridge.Tunnel, config *ServerConfig) interface{} {
+	switch config.Mode {
+	case "tunnelServer":
+		return NewTunnelModeServer(ProcessTunnel, Bridge, config)
+	case "socks5Server":
+		return NewSock5ModeServer(Bridge, config)
+	case "httpProxyServer":
+		return NewTunnelModeServer(ProcessHttp, Bridge, config)
+	case "udpServer":
+		return NewUdpModeServer(Bridge, config)
+	case "webServer":
+		InitCsvDb()
+		InitFromCsv()
+		//p, _ := beego.AppConfig.Int("hostPort")
+		t := &ServerConfig{
+			TcpPort:      8088,
+			Mode:         "httpHostServer",
+			Target:       "",
+			VerifyKey:    "",
+			U:            "",
+			P:            "",
+			Compress:     "",
+			Start:        1,
+			IsRun:        0,
+			ClientStatus: 0,
+		}
+		AddTask(t)
+		return NewWebServer(Bridge)
+	case "hostServer":
+		return NewHostServer(config)
+	case "httpHostServer":
+		return NewTunnelModeServer(ProcessHost, Bridge, config)
+	}
+	return nil
+}
+
+//stop server
+func StopServer(cFlag string) error {
+	if v, ok := RunList[cFlag]; ok {
+		reflect.ValueOf(v).MethodByName("Close").Call(nil)
+		delete(RunList, cFlag)
+		if VerifyKey == "" { //多客户端模式关闭相关隧道
+			Bridge.DelClientSignal(cFlag)
+			Bridge.DelClientTunnel(cFlag)
+		}
+		if t, err := CsvDb.GetTask(cFlag); err != nil {
+			return err
+		} else {
+			t.Start = 0
+			CsvDb.UpdateTask(t)
+		}
+		return nil
+	}
+	return errors.New("未在运行中")
+}
+
+//add task
+func AddTask(t *ServerConfig) error {
+	t.CompressDecode, t.CompressEncode = utils.GetCompressType(t.Compress)
+	if svr := NewMode(Bridge, t); svr != nil {
+		RunList[t.VerifyKey] = svr
+		go func() {
+			err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
+			if err.Interface() != nil {
+				log.Println("客户端", t.VerifyKey, "启动失败,错误:", err)
+				delete(RunList, t.VerifyKey)
+			}
+		}()
+	} else {
+		return errors.New("启动模式不正确")
+	}
+	return nil
+}
+
+//start task
+func StartTask(vKey string) error {
+	if t, err := CsvDb.GetTask(vKey); err != nil {
+		return err
+	} else {
+		AddTask(t)
+		t.Start = 1
+		CsvDb.UpdateTask(t)
+	}
+	return nil
+}
+
+//delete task
+func DelTask(vKey string) error {
+	if err := StopServer(vKey); err != nil {
+		return err
+	}
+	return CsvDb.DelTask(vKey)
+}
+
+//init csv from file
+func InitCsvDb() *Csv {
+	var once sync.Once
+	once.Do(func() {
+		CsvDb = NewCsv(RunList)
+		CsvDb.Init()
+	})
+	return CsvDb
+}
+
+//get key by host from x
+func GetKeyByHost(host string) (h *HostList, t *ServerConfig, err error) {
+	for _, v := range CsvDb.Hosts {
+		if strings.Contains(host, v.Host) {
+			h = v
+			t, err = CsvDb.GetTask(v.Vkey)
+			return
+		}
+	}
+	err = errors.New("未找到host对应的内网目标")
+	return
+}
+
+//get task list by page num
+func GetServerConfig(start, length int, typeVal string) ([]*ServerConfig, int) {
+	list := make([]*ServerConfig, 0)
+	var cnt int
+	for _, v := range CsvDb.Tasks {
+		if v.Mode != typeVal {
+			continue
+		}
+		cnt++
+		if start--; start < 0 {
+			if length--; length > 0 {
+				if _, ok := RunList[v.VerifyKey]; ok {
+					v.IsRun = 1
+				} else {
+					v.IsRun = 0
+				}
+				if s, ok := Bridge.SignalList[getverifyval(v.VerifyKey)]; ok {
+					if s.Len() > 0 {
+						v.ClientStatus = 1
+					} else {
+						v.ClientStatus = 0
+					}
+				} else {
+					v.ClientStatus = 0
+				}
+				list = append(list, v)
+			}
+		}
+
+	}
+	return list, cnt
+}
+
+//get verify value
+//when mode is webServer and vKey is not none
+func getverifyval(vkey string) string {
+	if VerifyKey != "" {
+		return utils.Md5(VerifyKey)
+	}
+	return utils.Md5(vkey)
+}

+ 16 - 13
lib/socks5.go → server/socks5.go

@@ -1,8 +1,10 @@
-package lib
+package server
 
 import (
 	"encoding/binary"
 	"errors"
+	"github.com/cnlh/easyProxy/bridge"
+	"github.com/cnlh/easyProxy/utils"
 	"io"
 	"log"
 	"net"
@@ -44,7 +46,7 @@ const (
 )
 
 type Sock5ModeServer struct {
-	bridge   *Tunnel
+	bridge   *bridge.Tunnel
 	isVerify bool
 	listener net.Listener
 	config   *ServerConfig
@@ -105,7 +107,7 @@ func (s *Sock5ModeServer) sendReply(c net.Conn, rep uint8) {
 }
 
 //do conn
-func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *Conn, err error) {
+func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *utils.Conn, err error) {
 	addrType := make([]byte, 1)
 	c.Read(addrType)
 	var host string
@@ -142,14 +144,14 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *Conn,
 	s.sendReply(c, succeeded)
 	var ltype string
 	if command == associateMethod {
-		ltype = CONN_UDP
+		ltype = utils.CONN_UDP
 	} else {
-		ltype = CONN_TCP
+		ltype = utils.CONN_TCP
 	}
 	_, err = client.WriteHost(ltype, addr)
 	var flag string
 	if flag, err = client.ReadFlag(); err == nil {
-		if flag != CONN_SUCCESS {
+		if flag != utils.CONN_SUCCESS {
 			err = errors.New("conn failed")
 		}
 	}
@@ -167,8 +169,8 @@ func (s *Sock5ModeServer) handleConnect(c net.Conn) {
 	if err != nil {
 		c.Close()
 	} else {
-		go relay(proxyConn.conn, c, s.config.CompressEncode, s.config.Crypt, s.config.Mux)
-		relay(c, proxyConn.conn, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
+		go utils.Relay(proxyConn.Conn, c, s.config.CompressEncode, s.config.Crypt, s.config.Mux)
+		utils.Relay(c, proxyConn.Conn, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
 	}
 }
 
@@ -205,13 +207,13 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) {
 	if err != nil {
 		c.Close()
 	} else {
-		go relay(proxyConn.conn, c, s.config.CompressEncode, s.config.Crypt, s.config.Mux)
-		relay(c, proxyConn.conn, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
+		go utils.Relay(proxyConn.Conn, c, s.config.CompressEncode, s.config.Crypt, s.config.Mux)
+		utils.Relay(c, proxyConn.Conn, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
 	}
 }
 
 //new conn
-func (s *Sock5ModeServer) handleNewConn(c net.Conn) {
+func (s *Sock5ModeServer) handleConn(c net.Conn) {
 	buf := make([]byte, 2)
 	if _, err := io.ReadFull(c, buf); err != nil {
 		log.Println("negotiation err", err)
@@ -285,6 +287,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))
 	if err != nil {
 		return err
@@ -297,7 +300,7 @@ func (s *Sock5ModeServer) Start() error {
 			}
 			log.Fatal("accept error: ", err)
 		}
-		go s.handleNewConn(conn)
+		go s.handleConn(conn)
 	}
 	return nil
 }
@@ -308,7 +311,7 @@ func (s *Sock5ModeServer) Close() error {
 }
 
 //new
-func NewSock5ModeServer(bridge *Tunnel, cnf *ServerConfig) *Sock5ModeServer {
+func NewSock5ModeServer(bridge *bridge.Tunnel, cnf *ServerConfig) *Sock5ModeServer {
 	s := new(Sock5ModeServer)
 	s.bridge = bridge
 	s.config = cnf

+ 191 - 0
server/tcp.go

@@ -0,0 +1,191 @@
+package server
+
+import (
+	"errors"
+	"fmt"
+	"github.com/astaxie/beego"
+	"github.com/cnlh/easyProxy/bridge"
+	"github.com/cnlh/easyProxy/utils"
+	"log"
+	"net"
+	"net/http"
+	"strings"
+)
+
+
+type process func(c *utils.Conn, s *TunnelModeServer) error
+
+type TunnelModeServer struct {
+	process  process
+	bridge   *bridge.Tunnel
+	config   *ServerConfig
+	listener *net.TCPListener
+}
+
+//tcp|http|host
+func NewTunnelModeServer(process process, bridge *bridge.Tunnel, cnf *ServerConfig) *TunnelModeServer {
+	s := new(TunnelModeServer)
+	s.bridge = bridge
+	s.process = process
+	s.config = cnf
+	return s
+}
+
+//开始
+func (s *TunnelModeServer) Start() error {
+	var err error
+	s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.config.TcpPort, ""})
+	if err != nil {
+		return err
+	}
+	for {
+		conn, err := s.listener.AcceptTCP()
+		if err != nil {
+			if strings.Contains(err.Error(), "use of closed network connection") {
+				break
+			}
+			log.Println(err)
+			continue
+		}
+		go s.process(utils.NewConn(conn), s)
+	}
+	return nil
+}
+
+//权限认证
+func (s *TunnelModeServer) auth(r *http.Request, c *utils.Conn, u, p string) error {
+	if u != "" && p != "" && !utils.CheckAuth(r, u, p) {
+		c.Write([]byte(utils.Unauthorized_BYTES))
+		c.Close()
+		return errors.New("401 Unauthorized")
+	}
+	return nil
+}
+
+//与客户端建立通道
+func (s *TunnelModeServer) dealClient(c *utils.Conn, cnf *ServerConfig, addr string, method string, rb []byte) error {
+	link, err := s.bridge.GetTunnel(getverifyval(cnf.VerifyKey), cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, cnf.Mux)
+	defer func() {
+		if cnf.Mux {
+			s.bridge.ReturnTunnel(link, getverifyval(cnf.VerifyKey))
+		} else {
+			c.Close()
+		}
+	}()
+	if err != nil {
+		log.Println(err)
+		c.Close()
+		return err
+	}
+	if _, err := link.WriteHost(utils.CONN_TCP, addr); err != nil {
+		c.Close()
+		link.Close()
+		log.Println(err)
+		return err
+	}
+	if flag, err := link.ReadFlag(); err == nil {
+		if flag == utils.CONN_SUCCESS {
+			if method == "CONNECT" {
+				fmt.Fprint(c, "HTTP/1.1 200 Connection established\r\n")
+			} else {
+				link.WriteTo(rb, cnf.CompressEncode, cnf.Crypt)
+			}
+			go utils.Relay(link.Conn, c.Conn, cnf.CompressEncode, cnf.Crypt, cnf.Mux)
+			utils.Relay(c.Conn, link.Conn, cnf.CompressDecode, cnf.Crypt, cnf.Mux)
+		}
+	}
+	return nil
+}
+
+//close
+func (s *TunnelModeServer) Close() error {
+	return s.listener.Close()
+}
+
+//tcp隧道模式
+func ProcessTunnel(c *utils.Conn, s *TunnelModeServer) error {
+	method, _, 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, method, rb)
+}
+
+//http代理模式
+func ProcessHttp(c *utils.Conn, s *TunnelModeServer) error {
+	method, addr, rb, err, r := c.GetHost()
+	if err != nil {
+		c.Close()
+		return err
+	}
+	if err := s.auth(r, c, s.config.U, s.config.P); err != nil {
+		return err
+	}
+	//TODO效率问题
+	return s.dealClient(c, s.config, addr, method, rb)
+}
+
+//多客户端域名代理
+func ProcessHost(c *utils.Conn, s *TunnelModeServer) error {
+	method, addr, rb, err, r := c.GetHost()
+	if err != nil {
+		c.Close()
+		return err
+	}
+	host, task, err := GetKeyByHost(addr)
+	if err != nil {
+		return err
+	}
+	if err := s.auth(r, c, task.U, task.P); err != nil {
+		return err
+	}
+	if err != nil {
+		c.Close()
+		return err
+	}
+	return s.dealClient(c, task, host.Target, method, rb)
+}
+
+//web管理方式
+type WebServer struct {
+	bridge *bridge.Tunnel
+}
+
+//开始
+func (s *WebServer) Start() {
+	beego.BConfig.WebConfig.Session.SessionOn = true
+	log.Println("web管理启动,访问端口为", beego.AppConfig.String("httpport"))
+	beego.SetViewsPath(beego.AppPath + "/web/views")
+	beego.SetStaticPath("/static/", "/web/static")
+	beego.Run()
+}
+
+//new
+func NewWebServer(bridge *bridge.Tunnel) *WebServer {
+	s := new(WebServer)
+	s.bridge = bridge
+	return s
+}
+
+//host
+type HostServer struct {
+	config *ServerConfig
+}
+
+//开始
+func (s *HostServer) Start() error {
+	return nil
+}
+
+func NewHostServer(cnf *ServerConfig) *HostServer {
+	s := new(HostServer)
+	s.config = cnf
+	return s
+}
+
+//close
+func (s *HostServer) Close() error {
+	return nil
+}

+ 11 - 8
lib/udp.go → server/udp.go

@@ -1,6 +1,8 @@
-package lib
+package server
 
 import (
+	"github.com/cnlh/easyProxy/bridge"
+	"github.com/cnlh/easyProxy/utils"
 	"io"
 	"log"
 	"net"
@@ -8,22 +10,23 @@ import (
 )
 
 type UdpModeServer struct {
-	bridge   *Tunnel
+	bridge   *bridge.Tunnel
 	listener *net.UDPConn
-	udpMap   map[string]*Conn
+	udpMap   map[string]*utils.Conn
 	config   *ServerConfig
 }
 
-func NewUdpModeServer(bridge *Tunnel, cnf *ServerConfig) *UdpModeServer {
+func NewUdpModeServer(bridge *bridge.Tunnel, cnf *ServerConfig) *UdpModeServer {
 	s := new(UdpModeServer)
 	s.bridge = bridge
-	s.udpMap = make(map[string]*Conn)
+	s.udpMap = make(map[string]*utils.Conn)
 	s.config = cnf
 	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, ""})
 	if err != nil {
 		return err
@@ -49,7 +52,7 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
 		log.Println(err)
 		return
 	}
-	if _, err := conn.WriteHost(CONN_UDP, s.config.Target); err != nil {
+	if _, err := conn.WriteHost(utils.CONN_UDP, s.config.Target); err != nil {
 		conn.Close()
 		return
 	}
@@ -61,7 +64,7 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
 				conn.Close()
 			}
 		}()
-		if flag == CONN_SUCCESS {
+		if flag == utils.CONN_SUCCESS {
 			conn.WriteTo(data, s.config.CompressEncode, s.config.Crypt)
 			buf := make([]byte, 1024)
 			//conn.conn.SetReadDeadline(time.Now().Add(time.Duration(time.Second * 3)))
@@ -71,7 +74,7 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
 				return
 			}
 			s.listener.WriteToUDP(buf[:n], addr)
-			conn.WriteTo([]byte(IO_EOF), s.config.CompressEncode, s.config.Crypt)
+			conn.WriteTo([]byte(utils.IO_EOF), s.config.CompressEncode, s.config.Crypt)
 		}
 	}
 }

+ 21 - 19
lib/conn.go → utils/conn.go

@@ -1,4 +1,4 @@
-package lib
+package utils
 
 import (
 	"bufio"
@@ -16,6 +16,8 @@ import (
 	"time"
 )
 
+const cryptKey = "1234567812345678"
+
 type CryptConn struct {
 	conn  net.Conn
 	crypt bool
@@ -126,13 +128,13 @@ func (s *SnappyConn) Read(b []byte) (n int, err error) {
 }
 
 type Conn struct {
-	conn net.Conn
+	Conn net.Conn
 }
 
 //new conn
 func NewConn(conn net.Conn) *Conn {
 	c := new(Conn)
-	c.conn = conn
+	c.Conn = conn
 	return c
 }
 
@@ -160,6 +162,7 @@ func (s *Conn) GetLen() (int, error) {
 //写入长度+内容 粘包
 func (s *Conn) WriteLen(buf []byte) (int, error) {
 	var b []byte
+	var err error
 	if b, err = GetLenBytes(buf); err != nil {
 		return 0, err
 	}
@@ -209,7 +212,7 @@ func (s *Conn) WriteHost(ltype string, host string) (int, error) {
 
 //设置连接为长连接
 func (s *Conn) SetAlive() {
-	conn := s.conn.(*net.TCPConn)
+	conn := s.Conn.(*net.TCPConn)
 	conn.SetReadDeadline(time.Time{})
 	conn.SetKeepAlive(true)
 	conn.SetKeepAlivePeriod(time.Duration(2 * time.Second))
@@ -247,17 +250,17 @@ func (s *Conn) GetHost() (method, address string, rb []byte, err error, r *http.
 //单独读(加密|压缩)
 func (s *Conn) ReadFrom(b []byte, compress int, crypt bool) (int, error) {
 	if COMPRESS_SNAPY_DECODE == compress {
-		return NewSnappyConn(s.conn, crypt).Read(b)
+		return NewSnappyConn(s.Conn, crypt).Read(b)
 	}
-	return NewCryptConn(s.conn, crypt).Read(b)
+	return NewCryptConn(s.Conn, crypt).Read(b)
 }
 
 //单独写(加密|压缩)
 func (s *Conn) WriteTo(b []byte, compress int, crypt bool) (n int, err error) {
 	if COMPRESS_SNAPY_ENCODE == compress {
-		return NewSnappyConn(s.conn, crypt).Write(b)
+		return NewSnappyConn(s.Conn, crypt).Write(b)
 	}
-	return NewCryptConn(s.conn, crypt).Write(b)
+	return NewCryptConn(s.Conn, crypt).Write(b)
 }
 
 //写压缩方式,加密
@@ -268,7 +271,6 @@ func (s *Conn) WriteConnInfo(en, de int, crypt, mux bool) {
 //获取压缩方式,是否加密
 func (s *Conn) GetConnInfoFromConn() (en, de int, crypt, mux bool) {
 	buf, err := s.ReadLen(4)
-	//TODO:错误处理
 	if err != nil {
 		return
 	}
@@ -281,51 +283,51 @@ func (s *Conn) GetConnInfoFromConn() (en, de int, crypt, mux bool) {
 
 //close
 func (s *Conn) Close() error {
-	return s.conn.Close()
+	return s.Conn.Close()
 }
 
 //write
 func (s *Conn) Write(b []byte) (int, error) {
-	return s.conn.Write(b)
+	return s.Conn.Write(b)
 }
 
 //read
 func (s *Conn) Read(b []byte) (int, error) {
-	return s.conn.Read(b)
+	return s.Conn.Read(b)
 }
 
 //write error
-func (s *Conn) wError() (int, error) {
+func (s *Conn) WriteError() (int, error) {
 	return s.Write([]byte(RES_MSG))
 }
 
 //write sign flag
-func (s *Conn) wSign() (int, error) {
+func (s *Conn) WriteSign() (int, error) {
 	return s.Write([]byte(RES_SIGN))
 }
 
 //write main
-func (s *Conn) wMain() (int, error) {
+func (s *Conn) WriteMain() (int, error) {
 	return s.Write([]byte(WORK_MAIN))
 }
 
 //write chan
-func (s *Conn) wChan() (int, error) {
+func (s *Conn) WriteChan() (int, error) {
 	return s.Write([]byte(WORK_CHAN))
 }
 
 //write test
-func (s *Conn) wTest() (int, error) {
+func (s *Conn) WriteTest() (int, error) {
 	return s.Write([]byte(TEST_FLAG))
 }
 
 //write test
-func (s *Conn) wSuccess() (int, error) {
+func (s *Conn) WriteSuccess() (int, error) {
 	return s.Write([]byte(CONN_SUCCESS))
 }
 
 //write test
-func (s *Conn) wFail() (int, error) {
+func (s *Conn) WriteFail() (int, error) {
 	return s.Write([]byte(CONN_ERROR))
 }
 

+ 2 - 2
lib/crypt.go → utils/crypt.go

@@ -1,4 +1,4 @@
-package lib
+package utils
 
 import (
 	"bytes"
@@ -6,7 +6,7 @@ import (
 	"crypto/cipher"
 	"crypto/md5"
 	"encoding/hex"
-	"github.com/pkg/errors"
+	"errors"
 	"math/rand"
 	"time"
 )

+ 204 - 0
utils/util.go

@@ -0,0 +1,204 @@
+package utils
+
+import (
+	"encoding/base64"
+	"io"
+	"log"
+	"net"
+	"net/http"
+	"regexp"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+const (
+	COMPRESS_NONE_ENCODE = iota
+	COMPRESS_NONE_DECODE
+	COMPRESS_SNAPY_ENCODE
+	COMPRESS_SNAPY_DECODE
+	VERIFY_EER         = "vkey"
+	WORK_MAIN          = "main"
+	WORK_CHAN          = "chan"
+	RES_SIGN           = "sign"
+	RES_MSG            = "msg0"
+	CONN_SUCCESS       = "sucs"
+	CONN_ERROR         = "fail"
+	TEST_FLAG          = "tst"
+	CONN_TCP           = "tcp"
+	CONN_UDP           = "udp"
+	Unauthorized_BYTES = `HTTP/1.1 401 Unauthorized
+Content-Type: text/plain; charset=utf-8
+WWW-Authenticate: Basic realm="easyProxy"
+
+401 Unauthorized`
+	IO_EOF = "PROXYEOF"
+)
+
+//copy
+func Relay(in, out net.Conn, compressType int, crypt, mux bool) {
+	switch compressType {
+	case COMPRESS_SNAPY_ENCODE:
+		copyBuffer(NewSnappyConn(in, crypt), out)
+		if mux {
+			out.Close()
+			NewSnappyConn(in, crypt).Write([]byte(IO_EOF))
+		}
+	case COMPRESS_SNAPY_DECODE:
+		copyBuffer(in, NewSnappyConn(out, crypt))
+		if mux {
+			in.Close()
+		}
+	case COMPRESS_NONE_ENCODE:
+		copyBuffer(NewCryptConn(in, crypt), out)
+		if mux {
+			out.Close()
+			NewCryptConn(in, crypt).Write([]byte(IO_EOF))
+		}
+	case COMPRESS_NONE_DECODE:
+		copyBuffer(in, NewCryptConn(out, crypt))
+		if mux {
+			in.Close()
+		}
+	}
+	if !mux {
+		in.Close()
+		out.Close()
+	}
+}
+
+//判断压缩方式
+func GetCompressType(compress string) (int, int) {
+	switch compress {
+	case "":
+		return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE
+	case "snappy":
+		return COMPRESS_SNAPY_DECODE, COMPRESS_SNAPY_ENCODE
+	default:
+		log.Fatalln("数据压缩格式错误")
+	}
+	return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE
+}
+
+//通过host获取对应的ip地址
+func Gethostbyname(hostname string) string {
+	if !DomainCheck(hostname) {
+		return hostname
+	}
+	ips, _ := net.LookupIP(hostname)
+	if ips != nil {
+		for _, v := range ips {
+			if v.To4() != nil {
+				return v.String()
+			}
+		}
+	}
+	return ""
+}
+
+//检查是否是域名
+func DomainCheck(domain string) bool {
+	var match bool
+	IsLine := "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}(/)"
+	NotLine := "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}"
+	match, _ = regexp.MatchString(IsLine, domain)
+	if !match {
+		match, _ = regexp.MatchString(NotLine, domain)
+	}
+	return match
+}
+
+//检查basic认证
+func CheckAuth(r *http.Request, user, passwd string) bool {
+	s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
+	if len(s) != 2 {
+		return false
+	}
+
+	b, err := base64.StdEncoding.DecodeString(s[1])
+	if err != nil {
+		return false
+	}
+
+	pair := strings.SplitN(string(b), ":", 2)
+	if len(pair) != 2 {
+		return false
+	}
+	return pair[0] == user && pair[1] == passwd
+}
+
+//get bool by str
+func GetBoolByStr(s string) bool {
+	switch s {
+	case "1", "true":
+		return true
+	}
+	return false
+}
+
+//get str by bool
+func GetStrByBool(b bool) string {
+	if b {
+		return "1"
+	}
+	return "0"
+}
+
+//int
+func GetIntNoerrByStr(str string) int {
+	i, _ := strconv.Atoi(str)
+	return i
+}
+
+var bufPool = sync.Pool{
+	New: func() interface{} {
+		return make([]byte, 65535)
+	},
+}
+// io.copy的优化版,读取buffer长度原为32*1024,与snappy不同,导致读取出的内容存在差异,不利于解密,特此修改
+func copyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
+	//TODO 回收问题
+	buf := bufPool.Get().([]byte)
+	for {
+		nr, er := src.Read(buf)
+		if nr > 0 {
+			nw, ew := dst.Write(buf[0:nr])
+			if nw > 0 {
+				written += int64(nw)
+			}
+			if ew != nil {
+				err = ew
+				break
+			}
+			if nr != nw {
+				err = io.ErrShortWrite
+				break
+			}
+		}
+		if er != nil {
+			if er != io.EOF {
+				err = er
+			}
+			break
+		}
+	}
+	return written, err
+}
+
+//连接重置 清空缓存区
+func FlushConn(c net.Conn) {
+	c.SetReadDeadline(time.Now().Add(time.Second * 3))
+	buf := bufPool.Get().([]byte)
+	for {
+		if _, err := c.Read(buf); err != nil {
+			break
+		}
+	}
+	c.SetReadDeadline(time.Time{})
+}
+
+//简单的一个校验值
+func Getverifyval(vkey string) string {
+	return Md5(vkey)
+}

+ 4 - 3
controllers/base.go → web/controllers/base.go

@@ -2,7 +2,8 @@ package controllers
 
 import (
 	"github.com/astaxie/beego"
-	"github.com/cnlh/easyProxy/lib"
+	"github.com/cnlh/easyProxy/server"
+	"github.com/cnlh/easyProxy/utils"
 	"strconv"
 	"strings"
 )
@@ -33,8 +34,8 @@ func (s *BaseController) display(tpl ...string) {
 	}
 	s.Data["menu"] = s.actionName
 	ip := s.Ctx.Request.Host
-	s.Data["ip"] = lib.Gethostbyname(ip[0:strings.LastIndex(ip, ":")])
-	s.Data["p"] = *lib.TcpPort
+	s.Data["ip"] = utils.Gethostbyname(ip[0:strings.LastIndex(ip, ":")])
+	s.Data["p"] = server.Bridge.TunnelPort
 	s.Data["proxyPort"] = beego.AppConfig.String("hostPort")
 	s.Layout = "public/layout.html"
 	s.TplName = tplname

+ 24 - 23
controllers/index.go → web/controllers/index.go

@@ -1,7 +1,8 @@
 package controllers
 
 import (
-	"github.com/cnlh/easyProxy/lib"
+	"github.com/cnlh/easyProxy/server"
+	"github.com/cnlh/easyProxy/utils"
 )
 
 type IndexController struct {
@@ -27,7 +28,7 @@ func (s *IndexController) Udp() {
 
 func (s *IndexController) Socks5() {
 	s.SetInfo("socks5管理")
-	s.SetType("sock5Server")
+	s.SetType("socks5Server")
 	s.display("index/list")
 }
 
@@ -46,7 +47,7 @@ func (s *IndexController) Host() {
 func (s *IndexController) GetServerConfig() {
 	start, length := s.GetAjaxParams()
 	taskType := s.GetString("type")
-	list, cnt := lib.CsvDb.GetServerConfig(start, length, taskType)
+	list, cnt := server.GetServerConfig(start, length, taskType)
 	s.AjaxTable(list, cnt, cnt)
 }
 
@@ -56,20 +57,20 @@ func (s *IndexController) Add() {
 		s.SetInfo("新增")
 		s.display()
 	} else {
-		t := &lib.ServerConfig{
+		t := &server.ServerConfig{
 			TcpPort:   s.GetIntNoErr("port"),
 			Mode:      s.GetString("type"),
 			Target:    s.GetString("target"),
-			VerifyKey: lib.GetRandomString(16),
+			VerifyKey: utils.GetRandomString(16),
 			U:         s.GetString("u"),
 			P:         s.GetString("p"),
 			Compress:  s.GetString("compress"),
-			Crypt:     lib.GetBoolByStr(s.GetString("crypt")),
-			Mux:     lib.GetBoolByStr(s.GetString("mux")),
+			Crypt:     utils.GetBoolByStr(s.GetString("crypt")),
+			Mux:       utils.GetBoolByStr(s.GetString("mux")),
 			IsRun:     0,
 		}
-		lib.CsvDb.NewTask(t)
-		if err := lib.AddTask(t); err != nil {
+		server.CsvDb.NewTask(t)
+		if err := server.AddTask(t); err != nil {
 			s.AjaxErr(err.Error())
 		} else {
 			s.AjaxOk("添加成功")
@@ -80,7 +81,7 @@ func (s *IndexController) Add() {
 func (s *IndexController) Edit() {
 	if s.Ctx.Request.Method == "GET" {
 		vKey := s.GetString("vKey")
-		if t, err := lib.CsvDb.GetTask(vKey); err != nil {
+		if t, err := server.CsvDb.GetTask(vKey); err != nil {
 			s.error()
 		} else {
 			s.Data["t"] = t
@@ -89,7 +90,7 @@ func (s *IndexController) Edit() {
 		s.display()
 	} else {
 		vKey := s.GetString("vKey")
-		if t, err := lib.CsvDb.GetTask(vKey); err != nil {
+		if t, err := server.CsvDb.GetTask(vKey); err != nil {
 			s.error()
 		} else {
 			t.TcpPort = s.GetIntNoErr("port")
@@ -98,11 +99,11 @@ func (s *IndexController) Edit() {
 			t.U = s.GetString("u")
 			t.P = s.GetString("p")
 			t.Compress = s.GetString("compress")
-			t.Crypt = lib.GetBoolByStr(s.GetString("crypt"))
-			t.Mux = lib.GetBoolByStr(s.GetString("mux"))
-			lib.CsvDb.UpdateTask(t)
-			lib.StopServer(t.VerifyKey)
-			lib.StartTask(t.VerifyKey)
+			t.Crypt = utils.GetBoolByStr(s.GetString("crypt"))
+			t.Mux = utils.GetBoolByStr(s.GetString("mux"))
+			server.CsvDb.UpdateTask(t)
+			server.StopServer(t.VerifyKey)
+			server.StartTask(t.VerifyKey)
 		}
 		s.AjaxOk("修改成功")
 	}
@@ -110,14 +111,14 @@ func (s *IndexController) Edit() {
 
 func (s *IndexController) Stop() {
 	vKey := s.GetString("vKey")
-	if err := lib.StopServer(vKey); err != nil {
+	if err := server.StopServer(vKey); err != nil {
 		s.AjaxErr("停止失败")
 	}
 	s.AjaxOk("停止成功")
 }
 func (s *IndexController) Del() {
 	vKey := s.GetString("vKey")
-	if err := lib.DelTask(vKey); err != nil {
+	if err := server.DelTask(vKey); err != nil {
 		s.AjaxErr("删除失败")
 	}
 	s.AjaxOk("删除成功")
@@ -125,7 +126,7 @@ func (s *IndexController) Del() {
 
 func (s *IndexController) Start() {
 	vKey := s.GetString("vKey")
-	if err := lib.StartTask(vKey); err != nil {
+	if err := server.StartTask(vKey); err != nil {
 		s.AjaxErr("开启失败")
 	}
 	s.AjaxOk("开启成功")
@@ -139,14 +140,14 @@ func (s *IndexController) HostList() {
 	} else {
 		start, length := s.GetAjaxParams()
 		vkey := s.GetString("vkey")
-		list, cnt := lib.CsvDb.GetHostList(start, length, vkey)
+		list, cnt := server.CsvDb.GetHostList(start, length, vkey)
 		s.AjaxTable(list, cnt, cnt)
 	}
 }
 
 func (s *IndexController) DelHost() {
 	host := s.GetString("host")
-	if err := lib.CsvDb.DelHost(host); err != nil {
+	if err := server.CsvDb.DelHost(host); err != nil {
 		s.AjaxErr("删除失败")
 	}
 	s.AjaxOk("删除成功")
@@ -158,12 +159,12 @@ func (s *IndexController) AddHost() {
 		s.SetInfo("新增")
 		s.display("index/hadd")
 	} else {
-		h := &lib.HostList{
+		h := &server.HostList{
 			Vkey:   s.GetString("vkey"),
 			Host:   s.GetString("host"),
 			Target: s.GetString("target"),
 		}
-		lib.CsvDb.NewHost(h)
+		server.CsvDb.NewHost(h)
 		s.AjaxOk("添加成功")
 	}
 }

+ 0 - 0
controllers/login.go → web/controllers/login.go


+ 1 - 1
routers/router.go → web/routers/router.go

@@ -2,7 +2,7 @@ package routers
 
 import (
 	"github.com/astaxie/beego"
-	"github.com/cnlh/easyProxy/controllers"
+	"github.com/cnlh/easyProxy/web/controllers"
 )
 
 func init() {

+ 0 - 0
static/css/font-awesome.min.css → web/static/css/font-awesome.min.css


+ 0 - 0
static/css/main.css → web/static/css/main.css


+ 0 - 0
static/fonts/FontAwesome.otf → web/static/fonts/FontAwesome.otf


+ 0 - 0
static/fonts/fontawesome-webfont.eot → web/static/fonts/fontawesome-webfont.eot


+ 0 - 0
static/fonts/fontawesome-webfont.svg → web/static/fonts/fontawesome-webfont.svg


+ 0 - 0
static/fonts/fontawesome-webfont.ttf → web/static/fonts/fontawesome-webfont.ttf


+ 0 - 0
static/fonts/fontawesome-webfont.woff → web/static/fonts/fontawesome-webfont.woff


+ 0 - 0
static/fonts/fontawesome-webfont.woff2 → web/static/fonts/fontawesome-webfont.woff2


+ 0 - 0
static/img/48.jpg → web/static/img/48.jpg


+ 0 - 0
static/img/favicon.ico → web/static/img/favicon.ico


+ 0 - 0
static/js/datatables.min.js → web/static/js/datatables.min.js


+ 0 - 0
static/js/main.js → web/static/js/main.js


+ 2 - 2
views/index/add.html → web/views/index/add.html

@@ -17,7 +17,7 @@
                         <select class="form-control" name="type" id="type">
                             <option {{if eq "tunnelServer" .type}}selected{{end}} value="tunnelServer">tcp隧道</option>
                             <option {{if eq "udpServer" .type}}selected{{end}} value="udpServer">udp隧道</option>
-                            <option {{if eq "sock5Server" .type}}selected{{end}} value="sock5Server">socks5代理</option>
+                            <option {{if eq "socks5Server" .type}}selected{{end}} value="socks5Server">socks5代理</option>
                             <option {{if eq "httpProxyServer" .type}}selected{{end}} value="httpProxyServer">http代理
                             <option {{if eq "hostServer" .type}}selected{{end}} value="hostServer">host客户端</option>
                         </select>
@@ -75,7 +75,7 @@
     arr["all"] = ["type", "port", "compress", "u", "p", "target"]
     arr["tunnelServer"] = ["type", "port", "target", "compress", "u", "p", "tcp隧道模式,提供一条tcp隧道,适用于ssh、远程桌面等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,访问公网服务器的设定端口,则相当于访问内网目标地址的目标端口"]
     arr["udpServer"] = ["type", "port", "target", "compress", "udp隧道模式,提供一条udp隧道,适用于dns、内网dns访问等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,访问公网服务器的设定端口,则相当于访问内网目标地址的udp目标端口"]
-    arr["sock5Server"] = ["type", "port", "compress", "u", "p", "socks5代理模式,内网socks5代理,配合proxifer,可如同使用vpn一样访问内网设备或资源,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置socks5代理,即访问内网设备或者资源 "]
+    arr["socks5Server"] = ["type", "port", "compress", "u", "p", "socks5代理模式,内网socks5代理,配合proxifer,可如同使用vpn一样访问内网设备或资源,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置socks5代理,即访问内网设备或者资源 "]
     arr["httpProxyServer"] = ["type", "port", "compress", "u", "p", " http代理模式,内网http代理,可访问内网网站,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置http代理,即访问内网站点"]
     arr["hostServer"] = ["type", "compress", "u", "p", "域名分发模式,使用域名代理内网服务,适用于小程序开发、公众号开发、站点演示等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,使用nginx将请求反向代理到本程序,再进行域名配置,即可解析"]
 

+ 2 - 2
views/index/edit.html → web/views/index/edit.html

@@ -10,7 +10,7 @@
                         <select class="form-control" name="type" id="type">
                             <option {{if eq "tunnelServer" .t.Mode}}selected{{end}} value="tunnelServer">tcp隧道</option>
                             <option {{if eq "udpServer" .t.Mode}}selected{{end}} value="udpServer">udp隧道</option>
-                            <option {{if eq "sock5Server" .t.Mode}}selected{{end}} value="sock5Server">socks5代理</option>
+                            <option {{if eq "socks5Server" .t.Mode}}selected{{end}} value="socks5Server">socks5代理</option>
                             <option {{if eq "httpProxyServer" .t.Mode}}selected{{end}} value="httpProxyServer">http代理
                             <option {{if eq "hostServer" .t.Mode}}selected{{end}} value="hostServer">host客户端</option>
                         </select>
@@ -72,7 +72,7 @@
     arr["all"] = ["type", "port", "compress", "u", "p", "target"]
     arr["tunnelServer"] = ["type", "port", "target", "u", "p", "compress"]
     arr["udpServer"] = ["type", "port", "target", "compress"]
-    arr["sock5Server"] = ["type", "port", "compress", "u", "p"]
+    arr["socks5Server"] = ["type", "port", "compress", "u", "p"]
     arr["httpProxyServer"] = ["type", "port", "compress", "u", "p"]
     arr["hostServer"] = ["type", "compress", "u", "p"]
 

+ 0 - 0
views/index/hadd.html → web/views/index/hadd.html


+ 0 - 0
views/index/hlist.html → web/views/index/hlist.html


+ 0 - 0
views/index/index.html → web/views/index/index.html


+ 0 - 0
views/index/list.html → web/views/index/list.html


+ 0 - 0
views/login/index.html → web/views/login/index.html


+ 0 - 0
views/public/error.html → web/views/public/error.html


+ 0 - 0
views/public/layout.html → web/views/public/layout.html