1
0
Эх сурвалжийг харах

加密传输,代码优化

刘河 6 жил өмнө
parent
commit
1d89e7dae2
16 өөрчлөгдсөн 724 нэмэгдсэн , 207 устгасан
  1. 10 2
      conf/app.conf
  2. 1 8
      conf/tasks.csv
  3. 2 0
      controllers/index.go
  4. 8 5
      lib/client.go
  5. 139 66
      lib/conn.go
  6. 86 0
      lib/crypt.go
  7. 318 0
      lib/file.go
  8. 19 11
      lib/init.go
  9. 20 14
      lib/server.go
  10. 8 6
      lib/sock5.go
  11. 2 2
      lib/tunnel.go
  12. 4 2
      lib/udp.go
  13. 78 87
      lib/util.go
  14. 7 1
      views/index/add.html
  15. 10 3
      views/index/edit.html
  16. 12 0
      views/index/list.html

+ 10 - 2
conf/app.conf

@@ -1,12 +1,20 @@
 appname = httpMonitor
+
 #web管理端口
 httpport = 8080
+
 #启动模式dev|pro
 runmode = dev
+
 #web管理密码
 password=123
+
 #http监听端口
 hostPort=8028
-#basic auth认证用户名和密码
+
+#basic auth认证用户名和密码,为空则不验证
 auth.user=test
-auth.password=1234
+auth.password=1234
+
+#是否加密传输(0|1)
+crypt=1

+ 1 - 8
conf/tasks.csv

@@ -1,8 +1 @@
-8021,tunnelServer,10.1.50.203:80,um80bbyvcaiw7n17,,,,1
-8001,tunnelServer,10.1.50.101:22,h8vcpciko9lczxmb,,,gzip,0
-8022,tunnelServer,10.1.50.196:4000,vcerzo01q16cdn9n,,,snappy,1
-8002,udpServer,10.1.50.102:53,zcbsx5kp53cg5yqv,,,,0
-8003,sock5Server,,9mq856pqq3jq05qv,,,snappy,1
-8010,sock5Server,,0aj2xfec0mbkann5,test,test,gzip,0
-8004,httpProxyServer,,y72zj8t074lslln0,,,gzip,0
-0,hostServer,,o2430bnq22jgnmcl,,,,1
+8001,tunnelServer,10.1.50.196:4000,jq5i7n0sjs1h0jje,,,,1,1

+ 2 - 0
controllers/index.go

@@ -64,6 +64,7 @@ func (s *IndexController) Add() {
 			U:         s.GetString("u"),
 			P:         s.GetString("p"),
 			Compress:  s.GetString("compress"),
+			Crypt:     s.GetString("crypt"),
 			IsRun:     0,
 		}
 		lib.CsvDb.NewTask(t)
@@ -96,6 +97,7 @@ func (s *IndexController) Edit() {
 			t.U = s.GetString("u")
 			t.P = s.GetString("p")
 			t.Compress = s.GetString("compress")
+			t.Crypt = s.GetString("crypt")
 			lib.CsvDb.UpdateTask(t)
 			lib.StopServer(t.VerifyKey)
 			lib.StartTask(t.VerifyKey)

+ 8 - 5
lib/client.go

@@ -86,10 +86,12 @@ func (s *TRPClient) dealChan() error {
 	//创建一个tcp连接
 	conn, err := net.Dial("tcp", s.svrAddr)
 	if err != nil {
+		log.Println("connect to ", s.svrAddr, "error:", err)
 		return err
 	}
 	//验证
 	if _, err := conn.Write([]byte(getverifyval(s.vKey))); err != nil {
+		log.Println("connect to ", s.svrAddr, "error:", err)
 		return err
 	}
 	//默认长连接保持
@@ -98,25 +100,26 @@ func (s *TRPClient) dealChan() error {
 	//写标志
 	c.wChan()
 	//获取连接的host type(tcp or udp)
-	typeStr, host, en, de, err := c.GetHostFromConn()
+	typeStr, host, en, de, crypt, err := c.GetHostFromConn()
 	if err != nil {
+		log.Println("get host info error:", err)
 		return err
 	}
 	//与目标建立连接
 	server, err := net.Dial(typeStr, host)
 	if err != nil {
-		log.Println(err)
+		log.Println("connect to ", host, "error:", err)
 		return err
 	}
-	go relay(NewConn(server), c, de)
-	relay(c, NewConn(server), en)
+	go relay(NewConn(server), c, de, crypt)
+	relay(c, NewConn(server), en, crypt)
 	return nil
 }
 
 //http模式处理
 func (s *TRPClient) dealHttp(c *Conn) error {
 	buf := make([]byte, 1024*32)
-	en, de := c.GetCompressTypeFromConn()
+	en, de, _ := c.GetConnInfoFromConn()
 	n, err := c.ReadFromCompress(buf, de)
 	if err != nil {
 		c.wError()

+ 139 - 66
lib/conn.go

@@ -8,7 +8,6 @@ import (
 	"errors"
 	"fmt"
 	"github.com/golang/snappy"
-	"io"
 	"log"
 	"net"
 	"net/http"
@@ -18,20 +17,76 @@ import (
 	"time"
 )
 
+type CryptConn struct {
+	conn  net.Conn
+	crypt bool
+}
+
+func NewCryptConn(conn net.Conn, crypt bool) *CryptConn {
+	c := new(CryptConn)
+	c.conn = conn
+	c.crypt = crypt
+	return c
+}
+
+func (s *CryptConn) Write(b []byte) (n int, err error) {
+	n = len(b)
+	if s.crypt {
+		if b, err = AesEncrypt(b, []byte(cryptKey)); err != nil {
+			return
+		}
+		if b, err = GetLenBytes(b); err != nil {
+			return
+		}
+	}
+	_, err = s.conn.Write(b)
+	return
+}
+
+func (s *CryptConn) Read(b []byte) (n int, err error) {
+	if s.crypt {
+		var lens int
+		var buf, bs []byte
+		c := NewConn(s.conn)
+		if lens, err = c.GetLen(); err != nil {
+			return
+		}
+		if buf, err = c.ReadLen(lens); err != nil {
+			return
+		}
+		if bs, err = AesDecrypt(buf, []byte(cryptKey)); err != nil {
+			return
+		}
+		n = len(bs)
+		copy(b, bs)
+		return
+	}
+	return s.conn.Read(b)
+}
+
 type SnappyConn struct {
-	w *snappy.Writer
-	r *snappy.Reader
+	w     *snappy.Writer
+	r     *snappy.Reader
+	crypt bool
 }
 
-func NewSnappyConn(conn net.Conn) *SnappyConn {
+func NewSnappyConn(conn net.Conn, crypt bool) *SnappyConn {
 	c := new(SnappyConn)
 	c.w = snappy.NewBufferedWriter(conn)
 	c.r = snappy.NewReader(conn)
+	c.crypt = crypt
 	return c
 }
 
 func (s *SnappyConn) Write(b []byte) (n int, err error) {
-	if n, err = s.w.Write(b); err != nil {
+	n = len(b)
+	if s.crypt {
+		if b, err = AesEncrypt(b, []byte(cryptKey)); err != nil {
+			log.Println("encode crypt error:", err)
+			return
+		}
+	}
+	if _, err = s.w.Write(b); err != nil {
 		return
 	}
 	err = s.w.Flush()
@@ -39,25 +94,42 @@ func (s *SnappyConn) Write(b []byte) (n int, err error) {
 }
 
 func (s *SnappyConn) Read(b []byte) (n int, err error) {
-	return s.r.Read(b)
+	if n, err = s.r.Read(b); err != nil {
+		return
+	}
+	if s.crypt {
+		var bs []byte
+		if bs, err = AesDecrypt(b[:n], []byte(cryptKey)); err != nil {
+			log.Println("decode crypt error:", err)
+			return
+		}
+		n = len(bs)
+		copy(b, bs)
+	}
+	return
 }
 
 type GzipConn struct {
-	w *gzip.Writer
-	r *gzip.Reader
+	w     *gzip.Writer
+	r     *gzip.Reader
+	crypt bool
 }
 
-func NewGzipConn(conn net.Conn) *GzipConn {
+func NewGzipConn(conn net.Conn, crypt bool) *GzipConn {
 	c := new(GzipConn)
+	c.crypt = crypt
 	c.w = gzip.NewWriter(conn)
 	c.r, err = gzip.NewReader(conn)
+	fmt.Println("err", err)
+	//错误处理
 	return c
 }
 
 func (s *GzipConn) Write(b []byte) (n int, err error) {
-	if n, err = s.w.Write(b); err != nil || err == io.EOF {
-		err = s.w.Flush()
-		s.w.Close()
+	fmt.Println(string(b))
+	if n, err = s.w.Write(b); err != nil {
+		//err = s.w.Flush()
+		//s.w.Close()
 		return
 	}
 	err = s.w.Flush()
@@ -65,7 +137,20 @@ func (s *GzipConn) Write(b []byte) (n int, err error) {
 }
 
 func (s *GzipConn) Read(b []byte) (n int, err error) {
-	return s.r.Read(b)
+	fmt.Println("read")
+	if n, err = s.r.Read(b); err != nil {
+		return
+	}
+	if s.crypt {
+		var bs []byte
+		if bs, err = AesDecrypt(b[:n], []byte(cryptKey)); err != nil {
+			log.Println("decode crypt error:", err)
+			return
+		}
+		n = len(bs)
+		copy(b, bs)
+	}
+	return
 }
 
 type Conn struct {
@@ -80,72 +165,49 @@ func NewConn(conn net.Conn) *Conn {
 
 //读取指定内容长度
 func (s *Conn) ReadLen(len int) ([]byte, error) {
-	raw := make([]byte, 0)
-	buff := make([]byte, 1024)
-	c := 0
-	for {
-		clen, err := s.Read(buff)
-		if err != nil && err != io.EOF {
-			return raw, err
-		}
-		raw = append(raw, buff[:clen]...)
-		if c += clen; c >= len {
-			break
-		}
-	}
-	if c != len {
-		return raw, errors.New(fmt.Sprintf("已读取长度错误,已读取%dbyte,需要读取%dbyte。", c, len))
+	buf := make([]byte, len)
+	if n, err := s.Read(buf); err != nil || n != len {
+		return buf, errors.New("读取指定长度错误" + err.Error())
 	}
-	return raw, nil
+	return buf, nil
 }
 
 //获取长度
 func (s *Conn) GetLen() (int, error) {
 	val := make([]byte, 4)
-	_, err := s.Read(val)
-	if err != nil {
+	if _, err := s.Read(val); err != nil {
 		return 0, err
 	}
-	nlen := binary.LittleEndian.Uint32(val)
-	if nlen <= 0 {
-		return 0, errors.New("数据长度错误")
-	}
-	return int(nlen), nil
+	return GetLenByBytes(val)
 }
 
 //写入长度
 func (s *Conn) WriteLen(buf []byte) (int, error) {
-	raw := bytes.NewBuffer([]byte{})
-	if err := binary.Write(raw, binary.LittleEndian, int32(len(buf))); err != nil {
-		log.Println(err)
+	var b []byte
+	if b, err = GetLenBytes(buf); err != nil {
 		return 0, err
 	}
-	if err = binary.Write(raw, binary.LittleEndian, buf); err != nil {
-		log.Println(err)
-		return 0, err
-	}
-	return s.Write(raw.Bytes())
+	return s.Write(b)
 }
 
 //读取flag
 func (s *Conn) ReadFlag() (string, error) {
 	val := make([]byte, 4)
-	_, err := s.Read(val)
-	if err != nil {
+	if _, err := s.Read(val); err != nil {
 		return "", err
 	}
 	return string(val), err
 }
 
 //读取host 连接地址 压缩类型
-func (s *Conn) GetHostFromConn() (typeStr string, host string, en, de int, err error) {
+func (s *Conn) GetHostFromConn() (typeStr string, host string, en, de int, crypt bool, err error) {
 retry:
 	ltype := make([]byte, 3)
 	if _, err = s.Read(ltype); err != nil {
 		return
 	}
 	if typeStr = string(ltype); typeStr == TEST_FLAG {
-		en, de = s.GetCompressTypeFromConn()
+		en, de, crypt = s.GetConnInfoFromConn()
 		goto retry
 	}
 	len, err := s.GetLen()
@@ -209,16 +271,10 @@ func (s *Conn) GetHost() (method, address string, rb []byte, err error, r *http.
 //压缩方式读
 func (s *Conn) ReadFromCompress(b []byte, compress int) (int, error) {
 	switch compress {
-	case COMPRESS_GZIP_DECODE:
-		r, err := gzip.NewReader(s)
-		if err != nil {
-			return 0, err
-		}
-		return r.Read(b)
 	case COMPRESS_SNAPY_DECODE:
 		r := snappy.NewReader(s)
 		return r.Read(b)
-	case COMPRESS_NONE:
+	default:
 		return s.Read(b)
 	}
 	return 0, nil
@@ -227,35 +283,30 @@ func (s *Conn) ReadFromCompress(b []byte, compress int) (int, error) {
 //压缩方式写
 func (s *Conn) WriteCompress(b []byte, compress int) (n int, err error) {
 	switch compress {
-	case COMPRESS_GZIP_ENCODE:
-		w := gzip.NewWriter(s)
-		if n, err = w.Write(b); err == nil {
-			w.Flush()
-		}
-		err = w.Close()
 	case COMPRESS_SNAPY_ENCODE:
 		w := snappy.NewBufferedWriter(s)
 		if n, err = w.Write(b); err == nil {
 			w.Flush()
 		}
 		err = w.Close()
-	case COMPRESS_NONE:
+	default:
 		n, err = s.Write(b)
 	}
 	return
 }
 
 //写压缩方式
-func (s *Conn) WriteCompressType(en, de int) {
-	s.Write([]byte(strconv.Itoa(en) + strconv.Itoa(de)))
+func (s *Conn) WriteConnInfo(en, de int, crypt bool) {
+	s.Write([]byte(strconv.Itoa(en) + strconv.Itoa(de) + GetStrByBool(crypt)))
 }
 
 //获取压缩方式
-func (s *Conn) GetCompressTypeFromConn() (en, de int) {
-	buf := make([]byte, 2)
+func (s *Conn) GetConnInfoFromConn() (en, de int, crypt bool) {
+	buf := make([]byte, 3)
 	s.Read(buf)
 	en, _ = strconv.Atoi(string(buf[0]))
 	de, _ = strconv.Atoi(string(buf[1]))
+	crypt = GetBoolByStr(string(buf[2]))
 	return
 }
 
@@ -290,3 +341,25 @@ func (s *Conn) wChan() (int, error) {
 func (s *Conn) wTest() (int, error) {
 	return s.Write([]byte(TEST_FLAG))
 }
+
+//获取长度+内容
+func GetLenBytes(buf []byte) (b []byte, err error) {
+	raw := bytes.NewBuffer([]byte{})
+	if err = binary.Write(raw, binary.LittleEndian, int32(len(buf))); err != nil {
+		return
+	}
+	if err = binary.Write(raw, binary.LittleEndian, buf); err != nil {
+		return
+	}
+	b = raw.Bytes()
+	return
+}
+
+//解析出长度
+func GetLenByBytes(buf []byte) (int, error) {
+	nlen := binary.LittleEndian.Uint32(buf)
+	if nlen <= 0 {
+		return 0, errors.New("数据长度错误")
+	}
+	return int(nlen), nil
+}

+ 86 - 0
lib/crypt.go

@@ -0,0 +1,86 @@
+package lib
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/md5"
+	"encoding/hex"
+	"math/rand"
+	"time"
+)
+
+func AesEncrypt(origData, key []byte) ([]byte, error) {
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	blockSize := block.BlockSize()
+	origData = PKCS5Padding(origData, blockSize)
+	// origData = ZeroPadding(origData, block.BlockSize())
+	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
+	crypted := make([]byte, len(origData))
+	// 根据CryptBlocks方法的说明,如下方式初始化crypted也可以
+	// crypted := origData
+	blockMode.CryptBlocks(crypted, origData)
+	return crypted, nil
+}
+
+func AesDecrypt(crypted, key []byte) ([]byte, error) {
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	blockSize := block.BlockSize()
+	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
+	origData := make([]byte, len(crypted))
+	// origData := crypted
+	blockMode.CryptBlocks(origData, crypted)
+	origData = PKCS5UnPadding(origData)
+	// origData = ZeroUnPadding(origData)
+	return origData, nil
+}
+
+func ZeroPadding(ciphertext []byte, blockSize int) []byte {
+	padding := blockSize - len(ciphertext)%blockSize
+	padtext := bytes.Repeat([]byte{0}, padding)
+	return append(ciphertext, padtext...)
+}
+
+func ZeroUnPadding(origData []byte) []byte {
+	length := len(origData)
+	unpadding := int(origData[length-1])
+	return origData[:(length - unpadding)]
+}
+
+func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
+	padding := blockSize - len(ciphertext)%blockSize
+	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
+	return append(ciphertext, padtext...)
+}
+
+func PKCS5UnPadding(origData []byte) []byte {
+	length := len(origData)
+	// 去掉最后一个字节 unpadding 次
+	unpadding := int(origData[length-1])
+	return origData[:(length - unpadding)]
+}
+
+//生成32位md5字串
+func Md5(s string) string {
+	h := md5.New()
+	h.Write([]byte(s))
+	return hex.EncodeToString(h.Sum(nil))
+}
+
+//生成随机验证密钥
+func GetRandomString(l int) string {
+	str := "0123456789abcdefghijklmnopqrstuvwxyz"
+	bytes := []byte(str)
+	result := []byte{}
+	r := rand.New(rand.NewSource(time.Now().UnixNano()))
+	for i := 0; i < l; i++ {
+		result = append(result, bytes[r.Intn(len(bytes))])
+	}
+	return string(result)
+}

+ 318 - 0
lib/file.go

@@ -0,0 +1,318 @@
+package lib
+
+import (
+	"encoding/csv"
+	"encoding/json"
+	"errors"
+	"io/ioutil"
+	"log"
+	"os"
+	"strconv"
+)
+
+type TaskList struct {
+	TcpPort      int    //服务端与客户端通信端口
+	Mode         string //启动方式
+	Target       string //目标
+	VerifyKey    string //flag
+	U            string //socks5验证用户名
+	P            string //socks5验证密码
+	Compress     string //压缩方式
+	Start        int    //是否开启
+	IsRun        int    //是否在运行
+	ClientStatus int    //客户端状态
+	Crypt        string //是否加密
+}
+
+type HostList struct {
+	Vkey   string //服务端与客户端通信端口
+	Host   string //启动方式
+	Target string //目标
+}
+
+func NewCsv(path string, bridge *Tunnel, runList map[string]interface{}) *Csv {
+	c := new(Csv)
+	c.Path = path
+	c.Bridge = bridge
+	c.RunList = runList
+	return c
+}
+
+type Csv struct {
+	Tasks   []*TaskList
+	Path    string
+	Bridge  *Tunnel
+	RunList map[string]interface{}
+	Hosts   []*HostList //域名列表
+}
+
+func (s *Csv) Init() {
+	s.LoadTaskFromCsv()
+	s.LoadHostFromCsv()
+}
+
+func (s *Csv) StoreTasksToCsv() {
+	// 创建文件
+	csvFile, err := os.Create(s.Path + "tasks.csv")
+	if err != nil {
+		log.Fatalf(err.Error())
+	}
+	defer csvFile.Close()
+	writer := csv.NewWriter(csvFile)
+	for _, task := range s.Tasks {
+		record := []string{
+			strconv.Itoa(task.TcpPort),
+			task.Mode,
+			task.Target,
+			task.VerifyKey,
+			task.U,
+			task.P,
+			task.Compress,
+			strconv.Itoa(task.Start),
+			task.Crypt,
+		}
+		err := writer.Write(record)
+		if err != nil {
+			log.Fatalf(err.Error())
+		}
+	}
+	writer.Flush()
+}
+
+func (s *Csv) LoadTaskFromCsv() {
+	// 打开文件
+	file, err := os.Open(s.Path + "tasks.csv")
+	if err != nil {
+		panic(err)
+	}
+	defer file.Close()
+
+	// 获取csv的reader
+	reader := csv.NewReader(file)
+
+	// 设置FieldsPerRecord为-1
+	reader.FieldsPerRecord = -1
+
+	// 读取文件中所有行保存到slice中
+	records, err := reader.ReadAll()
+	if err != nil {
+		panic(err)
+	}
+	var tasks []*TaskList
+	// 将每一行数据保存到内存slice中
+	for _, item := range records {
+		tcpPort, _ := strconv.Atoi(item[0])
+		Start, _ := strconv.Atoi(item[7])
+		post := &TaskList{
+			TcpPort:   tcpPort,
+			Mode:      item[1],
+			Target:    item[2],
+			VerifyKey: item[3],
+			U:         item[4],
+			P:         item[5],
+			Compress:  item[6],
+			Start:     Start,
+			Crypt:     item[8],
+		}
+		tasks = append(tasks, post)
+	}
+	s.Tasks = tasks
+}
+
+func (s *Csv) StoreHostToCsv() {
+	// 创建文件
+	csvFile, err := os.Create(s.Path + "hosts.csv")
+	if err != nil {
+		panic(err)
+	}
+	defer csvFile.Close()
+	// 获取csv的Writer
+	writer := csv.NewWriter(csvFile)
+	// 将map中的Post转换成slice,因为csv的Write需要slice参数
+	// 并写入csv文件
+	for _, host := range s.Hosts {
+		record := []string{
+			host.Host,
+			host.Target,
+			host.Vkey,
+		}
+		err1 := writer.Write(record)
+		if err1 != nil {
+			panic(err1)
+		}
+	}
+	// 确保所有内存数据刷到csv文件
+	writer.Flush()
+}
+
+func (s *Csv) LoadHostFromCsv() {
+	// 打开文件
+	file, err := os.Open(s.Path + "hosts.csv")
+	if err != nil {
+		panic(err)
+	}
+	defer file.Close()
+
+	// 获取csv的reader
+	reader := csv.NewReader(file)
+
+	// 设置FieldsPerRecord为-1
+	reader.FieldsPerRecord = -1
+
+	// 读取文件中所有行保存到slice中
+	records, err := reader.ReadAll()
+	if err != nil {
+		panic(err)
+	}
+	var hosts []*HostList
+	// 将每一行数据保存到内存slice中
+	for _, item := range records {
+		post := &HostList{
+			Vkey:   item[2],
+			Host:   item[0],
+			Target: item[1],
+		}
+		hosts = append(hosts, post)
+	}
+	s.Hosts = hosts
+}
+
+func (s *Csv) GetTaskList(start, length int, typeVal string) ([]*TaskList, int) {
+	list := make([]*TaskList, 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 *TaskList) {
+	s.Tasks = append(s.Tasks, t)
+	s.StoreTasksToCsv()
+}
+
+func (s *Csv) UpdateTask(t *TaskList) error {
+	for k, v := range s.Tasks {
+		if v.VerifyKey == t.VerifyKey {
+			s.Tasks = append(s.Tasks[:k], s.Tasks[k+1:]...)
+			s.Tasks = append(s.Tasks, t)
+			s.StoreTasksToCsv()
+			return nil
+		}
+	}
+	//TODO:待测试
+	return errors.New("不存在")
+}
+
+func (s *Csv) AddRunList(vKey string, svr interface{}) {
+	s.RunList[vKey] = svr
+}
+
+func (s *Csv) DelRunList(vKey string) {
+	delete(s.RunList, vKey)
+}
+
+func (s *Csv) DelTask(vKey string) error {
+	for k, v := range s.Tasks {
+		if v.VerifyKey == vKey {
+			s.Tasks = append(s.Tasks[:k], s.Tasks[k+1:]...)
+			s.StoreTasksToCsv()
+			return nil
+		}
+	}
+	return errors.New("不存在")
+}
+
+func (s *Csv) GetTask(vKey string) (v *TaskList, err error) {
+	for _, v = range s.Tasks {
+		if v.VerifyKey == vKey {
+			return
+		}
+	}
+	err = errors.New("未找到")
+	return
+}
+
+func (s *Csv) DelHost(host string) error {
+	for k, v := range s.Hosts {
+		if v.Host == host {
+			s.Hosts = append(s.Hosts[:k], s.Hosts[k+1:]...)
+			s.StoreHostToCsv()
+			return nil
+		}
+	}
+	return errors.New("不存在")
+}
+
+func (s *Csv) NewHost(t *HostList) {
+	s.Hosts = append(s.Hosts, t)
+	s.StoreHostToCsv()
+
+}
+
+func (s *Csv) GetHostList(start, length int, vKey string) ([]*HostList, int) {
+	list := make([]*HostList, 0)
+	var cnt int
+	for _, v := range s.Hosts {
+		if v.Vkey == vKey {
+			cnt++
+			if start--; start < 0 {
+				if length--; length > 0 {
+					list = append(list, v)
+				}
+			}
+		}
+	}
+	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
+}

+ 19 - 11
lib/init.go

@@ -21,13 +21,17 @@ var (
 	p            = flag.String("p", "", "socks5验证密码")
 	compress     = flag.String("compress", "", "数据压缩方式(gzip|snappy)")
 	serverAddr   = flag.String("server", "", "服务器地址ip:端口")
+	crypt        = flag.String("crypt", "", "是否加密(1|0)")
 	config       Config
 	err          error
 	RunList      map[string]interface{} //运行中的任务
 	bridge       *Tunnel
 	CsvDb        *Csv
+	//crypt        = GetBoolNoErrFromConfig("crypt")
 )
 
+const cryptKey = "1234567812345678"
+
 func init() {
 	RunList = make(map[string]interface{})
 }
@@ -52,7 +56,7 @@ func InitMode() {
 			log.Fatalln("服务端开启失败", err)
 		}
 		log.Println("服务端启动,监听tcp服务端端口:", *TcpPort)
-		if svr := newMode(*rpMode, bridge, *httpPort, *tunnelTarget, *u, *p, en, de, *verifyKey); svr != nil {
+		if svr := newMode(*rpMode, bridge, *httpPort, *tunnelTarget, *u, *p, en, de, *verifyKey, *crypt); svr != nil {
 			reflect.ValueOf(svr).MethodByName("Start").Call(nil)
 		} else {
 			log.Fatalln("启动模式不正确")
@@ -71,29 +75,33 @@ func InitFromCsv() {
 	}
 }
 
-func newMode(mode string, bridge *Tunnel, httpPort int, tunnelTarget string, u string, p string, enCompress int, deCompress int, vkey string) interface{} {
-	if u == "" || p == "" { //如果web管理中设置了用户名和密码,则覆盖配置文件
+func newMode(mode string, bridge *Tunnel, httpPort int, tunnelTarget string, u string, p string, enCompress int, deCompress int, vkey string, crypt string) interface{} {
+	if u == "" || p == "" { //如果web管理或者命令中设置了用户名和密码,则覆盖配置文件
 		u = beego.AppConfig.String("auth.user")
 		p = beego.AppConfig.String("auth.password")
 	}
+	if crypt == "" { //如果web管理或者命令中设置了是否加密,则覆盖配置文件
+		crypt = beego.AppConfig.String("crypt")
+	}
+	bCrypt := GetBoolByStr(crypt)
 	switch mode {
 	case "httpServer":
-		return NewHttpModeServer(httpPort, bridge, enCompress, deCompress, vkey)
+		return NewHttpModeServer(httpPort, bridge, enCompress, deCompress, vkey, bCrypt)
 	case "tunnelServer":
-		return NewTunnelModeServer(httpPort, tunnelTarget, ProcessTunnel, bridge, enCompress, deCompress, vkey, u, p)
+		return NewTunnelModeServer(httpPort, tunnelTarget, ProcessTunnel, bridge, enCompress, deCompress, vkey, u, p, bCrypt)
 	case "sock5Server":
-		return NewSock5ModeServer(httpPort, u, p, bridge, enCompress, deCompress, vkey)
+		return NewSock5ModeServer(httpPort, u, p, bridge, enCompress, deCompress, vkey, bCrypt)
 	case "httpProxyServer":
-		return NewTunnelModeServer(httpPort, tunnelTarget, ProcessHttp, bridge, enCompress, deCompress, vkey, u, p)
+		return NewTunnelModeServer(httpPort, tunnelTarget, ProcessHttp, bridge, enCompress, deCompress, vkey, u, p, bCrypt)
 	case "udpServer":
-		return NewUdpModeServer(httpPort, tunnelTarget, bridge, enCompress, deCompress, vkey)
+		return NewUdpModeServer(httpPort, tunnelTarget, bridge, enCompress, deCompress, vkey, bCrypt)
 	case "webServer":
 		InitCsvDb()
 		return NewWebServer(bridge)
 	case "hostServer":
-		return NewHostServer()
+		return NewHostServer(bCrypt)
 	case "httpHostServer":
-		return NewTunnelModeServer(httpPort, tunnelTarget, ProcessHost, bridge, enCompress, deCompress, vkey, u, p)
+		return NewTunnelModeServer(httpPort, tunnelTarget, ProcessHost, bridge, enCompress, deCompress, vkey, u, p, bCrypt)
 	}
 	return nil
 }
@@ -119,7 +127,7 @@ func StopServer(cFlag string) error {
 
 func AddTask(t *TaskList) error {
 	de, en := getCompressType(t.Compress)
-	if svr := newMode(t.Mode, bridge, t.TcpPort, t.Target, t.U, t.P, en, de, t.VerifyKey); svr != nil {
+	if svr := newMode(t.Mode, bridge, t.TcpPort, t.Target, t.U, t.P, en, de, t.VerifyKey, t.Crypt); svr != nil {
 		RunList[t.VerifyKey] = svr
 		go func() {
 			err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]

+ 20 - 14
lib/server.go

@@ -36,15 +36,17 @@ type HttpModeServer struct {
 	enCompress int
 	deCompress int
 	vKey       string
+	crypt      bool
 }
 
-func NewHttpModeServer(httpPort int, bridge *Tunnel, enCompress int, deCompress int, vKey string) *HttpModeServer {
+func NewHttpModeServer(httpPort int, bridge *Tunnel, enCompress int, deCompress int, vKey string, crypt bool) *HttpModeServer {
 	s := new(HttpModeServer)
 	s.bridge = bridge
 	s.httpPort = httpPort
 	s.enCompress = enCompress
 	s.deCompress = deCompress
 	s.vKey = vKey
+	s.crypt = crypt
 	return s
 }
 
@@ -90,7 +92,7 @@ func (s *HttpModeServer) writeRequest(r *http.Request, conn *Conn) error {
 		return err
 	}
 	conn.wSign()
-	conn.WriteCompressType(s.enCompress, s.deCompress)
+	conn.WriteConnInfo(s.enCompress, s.deCompress, s.crypt)
 	c, err := conn.WriteCompress(raw, s.enCompress)
 	if err != nil {
 		return err
@@ -152,9 +154,10 @@ type TunnelModeServer struct {
 	basicUser     string
 	basicPassword string
 	vKey          string
+	crypt         bool
 }
 
-func NewTunnelModeServer(httpPort int, tunnelTarget string, process process, bridge *Tunnel, enCompress, deCompress int, vKey, basicUser, basicPasswd string) *TunnelModeServer {
+func NewTunnelModeServer(httpPort int, tunnelTarget string, process process, bridge *Tunnel, enCompress, deCompress int, vKey, basicUser, basicPasswd string, crypt bool) *TunnelModeServer {
 	s := new(TunnelModeServer)
 	s.httpPort = httpPort
 	s.bridge = bridge
@@ -165,6 +168,7 @@ func NewTunnelModeServer(httpPort int, tunnelTarget string, process process, bri
 	s.vKey = vKey
 	s.basicUser = basicUser
 	s.basicPassword = basicPasswd
+	s.crypt = crypt
 	return s
 }
 
@@ -202,7 +206,7 @@ func (s *TunnelModeServer) Close() error {
 
 //tcp隧道模式
 func ProcessTunnel(c *Conn, s *TunnelModeServer) error {
-	link, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress)
+	link, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress, s.crypt)
 	if err != nil {
 		log.Println(err)
 		c.Close()
@@ -214,8 +218,8 @@ func ProcessTunnel(c *Conn, s *TunnelModeServer) error {
 		log.Println(err)
 		return err
 	}
-	go relay(link, c, s.enCompress)
-	relay(c, link, s.deCompress)
+	go relay(link, c, s.enCompress, s.crypt)
+	relay(c, link, s.deCompress, s.crypt)
 	return nil
 }
 
@@ -229,7 +233,7 @@ func ProcessHttp(c *Conn, s *TunnelModeServer) error {
 	if err := s.auth(r, c); err != nil {
 		return err
 	}
-	link, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress)
+	link, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress, s.crypt)
 	if err != nil {
 		log.Println(err)
 		c.Close()
@@ -246,8 +250,8 @@ func ProcessHttp(c *Conn, s *TunnelModeServer) error {
 	} else {
 		link.WriteCompress(rb, s.enCompress)
 	}
-	go relay(link, c, s.enCompress)
-	relay(c, link, s.deCompress)
+	go relay(link, c, s.enCompress, s.crypt)
+	relay(c, link, s.deCompress, s.crypt)
 	return nil
 }
 
@@ -267,7 +271,7 @@ func ProcessHost(c *Conn, s *TunnelModeServer) error {
 		return err
 	}
 	de, en := getCompressType(task.Compress)
-	link, err := s.bridge.GetTunnel(getverifyval(host.Vkey), en, de)
+	link, err := s.bridge.GetTunnel(getverifyval(host.Vkey), en, de, s.crypt)
 	if err != nil {
 		log.Println(err)
 		c.Close()
@@ -284,8 +288,8 @@ func ProcessHost(c *Conn, s *TunnelModeServer) error {
 	} else {
 		link.WriteCompress(rb, en)
 	}
-	go relay(link, c, en)
-	relay(c, link, de)
+	go relay(link, c, en, s.crypt)
+	relay(c, link, de, s.crypt)
 	return nil
 }
 
@@ -324,6 +328,7 @@ func NewWebServer(bridge *Tunnel) *WebServer {
 
 //host
 type HostServer struct {
+	crypt bool
 }
 
 //开始
@@ -331,9 +336,10 @@ func (s *HostServer) Start() error {
 	return nil
 }
 
-//TODO:host模式的客户端,无需指定和监听端口等,此处有待优化
-func NewHostServer() *HostServer {
+//TODO:host模式的客户端,无需指定和监听端口等
+func NewHostServer(crypt bool) *HostServer {
 	s := new(HostServer)
+	s.crypt = crypt
 	return s
 }
 

+ 8 - 6
lib/sock5.go

@@ -53,6 +53,7 @@ type Sock5ModeServer struct {
 	isVerify   bool
 	listener   net.Listener
 	vKey       string
+	crypt      bool
 }
 
 func (s *Sock5ModeServer) handleRequest(c net.Conn) {
@@ -136,7 +137,7 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *Conn,
 	binary.Read(c, binary.BigEndian, &port)
 	// connect to host
 	addr := net.JoinHostPort(host, strconv.Itoa(int(port)))
-	client, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress)
+	client, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress, s.crypt)
 	if err != nil {
 		log.Println(err)
 		client.Close()
@@ -159,8 +160,8 @@ func (s *Sock5ModeServer) handleConnect(c net.Conn) {
 		log.Println(err)
 		c.Close()
 	} else {
-		go relay(proxyConn, NewConn(c), s.enCompress)
-		go relay(NewConn(c), proxyConn, s.deCompress)
+		go relay(proxyConn, NewConn(c), s.enCompress, s.crypt)
+		go relay(NewConn(c), proxyConn, s.deCompress, s.crypt)
 	}
 
 }
@@ -192,8 +193,8 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) {
 	if err != nil {
 		c.Close()
 	} else {
-		go relay(proxyConn, NewConn(c), s.enCompress)
-		go relay(NewConn(c), proxyConn, s.deCompress)
+		go relay(proxyConn, NewConn(c), s.enCompress, s.crypt)
+		go relay(NewConn(c), proxyConn, s.deCompress, s.crypt)
 	}
 }
 
@@ -290,7 +291,7 @@ func (s *Sock5ModeServer) Close() error {
 	return s.listener.Close()
 }
 
-func NewSock5ModeServer(httpPort int, u, p string, brige *Tunnel, enCompress int, deCompress int, vKey string) *Sock5ModeServer {
+func NewSock5ModeServer(httpPort int, u, p string, brige *Tunnel, enCompress int, deCompress int, vKey string, crypt bool) *Sock5ModeServer {
 	s := new(Sock5ModeServer)
 	s.httpPort = httpPort
 	s.bridge = brige
@@ -304,5 +305,6 @@ func NewSock5ModeServer(httpPort int, u, p string, brige *Tunnel, enCompress int
 	s.enCompress = enCompress
 	s.deCompress = deCompress
 	s.vKey = vKey
+	s.crypt = crypt
 	return s
 }

+ 2 - 2
lib/tunnel.go

@@ -141,7 +141,7 @@ retry:
 }
 
 //得到一个tcp隧道
-func (s *Tunnel) GetTunnel(cFlag string, en, de int) (c *Conn, err error) {
+func (s *Tunnel) GetTunnel(cFlag string, en, de int, crypt bool) (c *Conn, err error) {
 	if v, ok := s.tunnelList[cFlag]; !ok || v.Len() < 10 { //新建通道
 		go s.newChan(cFlag)
 	}
@@ -154,7 +154,7 @@ retry:
 		c.Close()
 		goto retry
 	}
-	c.WriteCompressType(en, de)
+	c.WriteConnInfo(en, de, crypt)
 	return
 }
 

+ 4 - 2
lib/udp.go

@@ -18,9 +18,10 @@ type UdpModeServer struct {
 	enCompress   int
 	deCompress   int
 	vKey         string
+	crypt        bool
 }
 
-func NewUdpModeServer(udpPort int, tunnelTarget string, bridge *Tunnel, enCompress int, deCompress int, vKey string) *UdpModeServer {
+func NewUdpModeServer(udpPort int, tunnelTarget string, bridge *Tunnel, enCompress int, deCompress int, vKey string, crypt bool) *UdpModeServer {
 	s := new(UdpModeServer)
 	s.udpPort = udpPort
 	s.tunnelTarget = tunnelTarget
@@ -29,6 +30,7 @@ func NewUdpModeServer(udpPort int, tunnelTarget string, bridge *Tunnel, enCompre
 	s.enCompress = enCompress
 	s.deCompress = deCompress
 	s.vKey = vKey
+	s.crypt = crypt
 	return s
 }
 
@@ -57,7 +59,7 @@ func (s *UdpModeServer) Start() error {
 func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
 	fmt.Println(addr.String())
 	fmt.Println(string(data))
-	conn, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress)
+	conn, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress, s.crypt)
 	if err != nil {
 		log.Println(err)
 		return

+ 78 - 87
lib/util.go

@@ -3,18 +3,12 @@ package lib
 import (
 	"bufio"
 	"bytes"
-	"compress/gzip"
-	"crypto/md5"
 	"encoding/base64"
 	"encoding/binary"
-	"encoding/hex"
-	"encoding/json"
 	"errors"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"log"
-	"math/rand"
 	"net"
 	"net/http"
 	"net/http/httputil"
@@ -22,19 +16,25 @@ import (
 	"regexp"
 	"strconv"
 	"strings"
-	"time"
+	"sync"
 )
 
 var (
 	disabledRedirect = errors.New("disabled redirect.")
+	bufPool          = &sync.Pool{
+		New: func() interface{} {
+			return make([]byte, 32*1024)
+		},
+	}
 )
+//pool 实现
+type bufType [32 * 1024]byte
 
 const (
-	COMPRESS_NONE = iota
+	COMPRESS_NONE_ENCODE = iota
+	COMPRESS_NONE_DECODE
 	COMPRESS_SNAPY_ENCODE
 	COMPRESS_SNAPY_DECODE
-	COMPRESS_GZIP_ENCODE
-	COMPRESS_GZIP_DECODE
 )
 
 func BadRequest(w http.ResponseWriter) {
@@ -134,83 +134,36 @@ func replaceHost(resp []byte) []byte {
 	return []byte(str)
 }
 
-func relay(in, out *Conn, compressType int) {
-	buf := make([]byte, 32*1024)
+func relay(in, out *Conn, compressType int, crypt bool) {
+	fmt.Println(crypt)
 	switch compressType {
-	case COMPRESS_GZIP_ENCODE:
-		//TODO:GZIP压缩存在问题有待解决
-		w := gzip.NewWriter(in)
-		for {
-			n, err := out.Read(buf)
-			if err != nil || err == io.EOF {
-				break
-			}
-			if _, err = w.Write(buf[:n]); err != nil {
-				break
-			}
-			if err = w.Flush(); err != nil {
-				log.Println(err)
-				break
-			}
-		}
-		w.Close()
 	case COMPRESS_SNAPY_ENCODE:
-		io.Copy(NewSnappyConn(in.conn), out)
-	case COMPRESS_GZIP_DECODE:
-		io.Copy(in, NewGzipConn(out.conn))
+		copyBuffer(NewSnappyConn(in.conn, crypt), out)
 	case COMPRESS_SNAPY_DECODE:
-		io.Copy(in, NewSnappyConn(out.conn))
-	default:
-		io.Copy(in, out)
+		copyBuffer(in, NewSnappyConn(out.conn, crypt))
+	case COMPRESS_NONE_ENCODE:
+		copyBuffer(NewCryptConn(in.conn, crypt), out)
+	case COMPRESS_NONE_DECODE:
+		copyBuffer(in, NewCryptConn(out.conn, crypt))
 	}
 	out.Close()
 	in.Close()
 }
 
-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
-}
-
 //判断压缩方式
 func getCompressType(compress string) (int, int) {
 	switch compress {
 	case "":
-		return COMPRESS_NONE, COMPRESS_NONE
-	case "gzip":
-		return COMPRESS_GZIP_DECODE, COMPRESS_GZIP_ENCODE
+		return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE
 	case "snappy":
 		return COMPRESS_SNAPY_DECODE, COMPRESS_SNAPY_ENCODE
 	default:
 		log.Fatalln("数据压缩格式错误")
 	}
-	return COMPRESS_NONE, COMPRESS_NONE
+	return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE
 }
 
-// 简单的一个校验值
+//简单的一个校验值
 func getverifyval(vkey string) string {
 	//单客户端模式
 	if *verifyKey != "" {
@@ -219,6 +172,7 @@ func getverifyval(vkey string) string {
 	return Md5(vkey)
 }
 
+//验证
 func verify(verifyKeyMd5 string) bool {
 	if *verifyKey != "" && getverifyval(*verifyKey) == verifyKeyMd5 {
 		return true
@@ -233,6 +187,7 @@ func verify(verifyKeyMd5 string) bool {
 	return false
 }
 
+//get key by host from x
 func getKeyByHost(host string) (h *HostList, t *TaskList, err error) {
 	for _, v := range CsvDb.Hosts {
 		if strings.Contains(host, v.Host) {
@@ -245,25 +200,6 @@ func getKeyByHost(host string) (h *HostList, t *TaskList, err error) {
 	return
 }
 
-//生成32位md5字串
-func Md5(s string) string {
-	h := md5.New()
-	h.Write([]byte(s))
-	return hex.EncodeToString(h.Sum(nil))
-}
-
-//生成随机验证密钥
-func GetRandomString(l int) string {
-	str := "0123456789abcdefghijklmnopqrstuvwxyz"
-	bytes := []byte(str)
-	result := []byte{}
-	r := rand.New(rand.NewSource(time.Now().UnixNano()))
-	for i := 0; i < l; i++ {
-		result = append(result, bytes[r.Intn(len(bytes))])
-	}
-	return string(result)
-}
-
 //通过host获取对应的ip地址
 func Gethostbyname(hostname string) string {
 	if !DomainCheck(hostname) {
@@ -310,3 +246,58 @@ func checkAuth(r *http.Request, user, passwd string) bool {
 	}
 	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"
+}
+
+// io.copy的优化版,读取buffer长度原为32*1024,与snappy不同,导致读取出的内容存在差异,不利于解密
+func copyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
+	// If the reader has a WriteTo method, use it to do the copy.
+	// Avoids an allocation and a copy.
+	if wt, ok := src.(io.WriterTo); ok {
+		return wt.WriteTo(dst)
+	}
+	// Similarly, if the writer has a ReadFrom method, use it to do the copy.
+	if rt, ok := dst.(io.ReaderFrom); ok {
+		return rt.ReadFrom(src)
+	}
+	buf := make([]byte, 65535)
+	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
+}

+ 7 - 1
views/index/add.html

@@ -34,10 +34,16 @@
                         <label class="control-label">数据压缩方式</label>
                         <select class="form-control" name="compress">
                             <option value="">不压缩</option>
-                            <option value="gzip">gzip压缩</option>
                             <option value="snappy">snappy</option>
                         </select>
                     </div>
+                    <div class="form-group" id="compress">
+                        <label class="control-label">是否加密传输</label>
+                        <select class="form-control" name="crypt">
+                            <option value="0">不加密</option>
+                            <option value="1">加密</option>
+                        </select>
+                    </div>
                     <div class="form-group" id="u">
                         <label class="control-label">验证用户名(socks5、HTTP代理模式)</label>
                         <input class="form-control" type="text" name="u" placeholder="不填则无需验证">

+ 10 - 3
views/index/edit.html

@@ -7,7 +7,7 @@
                     <input type="hidden" name="vKey" value="{{.t.VerifyKey}}">
                     <div class="form-group">
                         <label class="control-label">模式</label>
-                        <select class="form-control" name="type"  id="type">
+                        <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>
@@ -29,10 +29,16 @@
                         <label class="control-label">数据压缩方式(所有模式均支持)</label>
                         <select class="form-control" name="compress">
                             <option {{if eq "" .t.Compress}}selected{{end}} value="">不压缩</option>
-                            <option {{if eq "gzip" .t.Compress}}selected{{end}} value="gzip">gzip压缩</option>
                             <option {{if eq "snappy" .t.Compress}}selected{{end}} value="snappy">snappy压缩</option>
                         </select>
                     </div>
+                    <div class="form-group" id="compress">
+                        <label class="control-label">是否加密传输(所有模式均支持)</label>
+                        <select class="form-control" name="crypt">
+                            <option {{if eq "0" .t.Crypt}}selected{{end}} value="0">不加密</option>
+                            <option {{if eq "1" .t.Crypt}}selected{{end}} value="1">加密</option>
+                        </select>
+                    </div>
                     <div class="form-group" id="u">
                         <label class="control-label">验证用户名(socks5、HTTP代理模式)</label>
                         <input class="form-control" value="{{.t.U}}" type="text" name="u"
@@ -56,7 +62,7 @@
 </main>
 <script>
     var arr = []
-    arr["all"] = ["type", "port", "compress", "u", "p","target"]
+    arr["all"] = ["type", "port", "compress", "u", "p", "target"]
     arr["tunnelServer"] = ["type", "port", "target", "compress"]
     arr["udpServer"] = ["type", "port", "target", "compress"]
     arr["sock5Server"] = ["type", "port", "compress", "u", "p"]
@@ -72,6 +78,7 @@
             $("#" + arr[o][i]).css("display", "block")
         }
     }
+
     $(function () {
         resetForm()
         $("#type").on("change", function () {

+ 12 - 0
views/index/list.html

@@ -10,6 +10,7 @@
                         <th>内网目标</th>
                         <th>多客户端模式客户端执行命令</th>
                         <th>压缩方式</th>
+                        <th>加密传输</th>
                         <th>用户名</th>
                         <th>密码</th>
                         <th>客户端状态</th>
@@ -106,6 +107,7 @@
                 {data: 'Target'},
                 {data: 'VerifyKey'},
                 {data: 'Compress'},
+                {data: 'Crypt'},
                 {data: 'U'},
                 {data: 'P'},
                 {data: 'ClientStatus'},
@@ -146,6 +148,16 @@
                         }
                     }
                 },
+                {
+                    targets: -6,
+                    render: function (data, type, row, meta) {
+                        if (data == "0") {
+                            return "不加密"
+                        } else {
+                            return "加密"
+                        }
+                    }
+                },
                 {
                     targets: 2,
                     render: function (data, type, row, meta) {