Przeglądaj źródła

Tcp多路复用

刘河 6 lat temu
rodzic
commit
9bec5366a6
14 zmienionych plików z 271 dodań i 187 usunięć
  1. 3 3
      conf/tasks.csv
  2. 7 5
      controllers/index.go
  3. 11 4
      lib/bridge.go
  4. 23 7
      lib/client.go
  5. 21 7
      lib/conn.go
  6. 39 30
      lib/file.go
  7. 36 19
      lib/init.go
  8. 21 28
      lib/socks5.go
  9. 38 55
      lib/tcp.go
  10. 16 21
      lib/udp.go
  11. 25 4
      lib/util.go
  12. 7 0
      views/index/add.html
  13. 9 2
      views/index/edit.html
  14. 15 2
      views/index/list.html

+ 3 - 3
conf/tasks.csv

@@ -1,3 +1,3 @@
-0,hostServer,,ts08z6vk5nc72fs8,aaa,bbb,,1,0
-0,hostServer,,7n7bxc2bm1fyjfab,a,b,,1,0
-8001,tunnelServer,127.0.0.1:88,jq5i7n0sjs1h0jje,aaa,bbb,,1,1
+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

+ 7 - 5
controllers/index.go

@@ -43,10 +43,10 @@ func (s *IndexController) Host() {
 	s.display("index/list")
 }
 
-func (s *IndexController) GetTaskList() {
+func (s *IndexController) GetServerConfig() {
 	start, length := s.GetAjaxParams()
 	taskType := s.GetString("type")
-	list, cnt := lib.CsvDb.GetTaskList(start, length, taskType)
+	list, cnt := lib.CsvDb.GetServerConfig(start, length, taskType)
 	s.AjaxTable(list, cnt, cnt)
 }
 
@@ -56,7 +56,7 @@ func (s *IndexController) Add() {
 		s.SetInfo("新增")
 		s.display()
 	} else {
-		t := &lib.TaskList{
+		t := &lib.ServerConfig{
 			TcpPort:   s.GetIntNoErr("port"),
 			Mode:      s.GetString("type"),
 			Target:    s.GetString("target"),
@@ -64,7 +64,8 @@ func (s *IndexController) Add() {
 			U:         s.GetString("u"),
 			P:         s.GetString("p"),
 			Compress:  s.GetString("compress"),
-			Crypt:     s.GetString("crypt"),
+			Crypt:     lib.GetBoolByStr(s.GetString("crypt")),
+			Mux:     lib.GetBoolByStr(s.GetString("mux")),
 			IsRun:     0,
 		}
 		lib.CsvDb.NewTask(t)
@@ -97,7 +98,8 @@ func (s *IndexController) Edit() {
 			t.U = s.GetString("u")
 			t.P = s.GetString("p")
 			t.Compress = s.GetString("compress")
-			t.Crypt = s.GetString("crypt")
+			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)

+ 11 - 4
lib/tunnel.go → lib/bridge.go

@@ -141,8 +141,8 @@ retry:
 }
 
 //得到一个tcp隧道
-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 { //新建通道
+func (s *Tunnel) GetTunnel(cFlag string, en, de int, crypt, mux bool) (c *Conn, err error) {
+	if v, ok := s.tunnelList[cFlag]; !ok || v.Len() < 3 { //新建通道
 		go s.newChan(cFlag)
 	}
 retry:
@@ -150,11 +150,11 @@ retry:
 		return
 	}
 	c = s.tunnelList[cFlag].Pop()
-	if _, err := c.wTest(); err != nil {
+	if _, err = c.wTest(); err != nil {
 		c.Close()
 		goto retry
 	}
-	c.WriteConnInfo(en, de, crypt)
+	c.WriteConnInfo(en, de, crypt, mux)
 	return
 }
 
@@ -175,6 +175,13 @@ func (s *Tunnel) ReturnSignal(conn *Conn, cFlag string) {
 	}
 }
 
+//重回slice 复用
+func (s *Tunnel) ReturnTunnel(conn *Conn, cFlag string) {
+	if v, ok := s.tunnelList[cFlag]; ok {
+		v.Add(conn)
+	}
+}
+
 //删除通信通道
 func (s *Tunnel) DelClientSignal(cFlag string) {
 	s.delClient(cFlag, s.signalList)

+ 23 - 7
lib/client.go

@@ -102,27 +102,43 @@ func (s *TRPClient) dealChan() error {
 	c.SetAlive()
 	//写标志
 	c.wChan()
+re:
 	//获取连接的host type(tcp or udp)
-	typeStr, host, en, de, crypt, err := c.GetHostFromConn()
+	typeStr, host, en, de, crypt, mux, err := c.GetHostFromConn()
 	if err != nil {
 		log.Println("get host info error:", err)
 		return err
 	}
-	//与目标建立连接
-	server, err := net.Dial(typeStr, host)
+	//与目标建立连接,超时时间为3
+	server, err := net.DialTimeout(typeStr, host, time.Second*3)
 	if err != nil {
-		log.Println("connect to ", host, "error:", err)
+		log.Println("connect to ", host, "error:", err, mux)
+		if mux {
+			s.sendEof(conn, de, crypt)
+			goto re
+		}
 		return err
 	}
-	go relay(NewConn(server), c, de, crypt)
-	relay(c, NewConn(server), en, crypt)
+	go relay(NewConn(server), c, de, crypt, mux)
+	relay(c, NewConn(server), en, crypt, mux)
+	if mux {
+		goto re
+	}
 	return nil
 }
+func (s *TRPClient) sendEof(c net.Conn, de int, crypt bool) {
+	switch de {
+	case COMPRESS_SNAPY_DECODE:
+		NewSnappyConn(c, crypt).Write([]byte(IO_EOF))
+	case COMPRESS_NONE_DECODE:
+		NewCryptConn(c, crypt).Write([]byte(IO_EOF))
+	}
+}
 
 //http模式处理
 func (s *TRPClient) dealHttp(c *Conn) error {
 	buf := make([]byte, 1024*32)
-	en, de, crypt := c.GetConnInfoFromConn()
+	en, de, crypt, _ := c.GetConnInfoFromConn()
 	n, err := c.ReadFrom(buf, de, crypt)
 	if err != nil {
 		c.wError()

+ 21 - 7
lib/conn.go

@@ -45,6 +45,12 @@ func (s *CryptConn) Write(b []byte) (n int, err error) {
 
 //解密读
 func (s *CryptConn) Read(b []byte) (n int, err error) {
+	defer func() {
+		if string(b[:n]) == IO_EOF {
+			err = io.EOF
+			n = 0
+		}
+	}()
 	if s.crypt {
 		var lens int
 		var buf, bs []byte
@@ -62,7 +68,8 @@ func (s *CryptConn) Read(b []byte) (n int, err error) {
 		copy(b, bs)
 		return
 	}
-	return s.conn.Read(b)
+	n, err = s.conn.Read(b)
+	return
 }
 
 type SnappyConn struct {
@@ -97,6 +104,12 @@ func (s *SnappyConn) Write(b []byte) (n int, err error) {
 
 //snappy压缩读 包含解密
 func (s *SnappyConn) Read(b []byte) (n int, err error) {
+	defer func() {
+		if string(b[:n]) == IO_EOF {
+			err = io.EOF
+			n = 0
+		}
+	}()
 	if n, err = s.r.Read(b); err != nil {
 		return
 	}
@@ -160,14 +173,14 @@ func (s *Conn) ReadFlag() (string, error) {
 }
 
 //读取host 连接地址 压缩类型
-func (s *Conn) GetHostFromConn() (typeStr string, host string, en, de int, crypt bool, err error) {
+func (s *Conn) GetHostFromConn() (typeStr string, host string, en, de int, crypt, mux bool, err error) {
 retry:
 	lType, err := s.ReadLen(3)
 	if err != nil {
 		return
 	}
 	if typeStr = string(lType); typeStr == TEST_FLAG {
-		en, de, crypt = s.GetConnInfoFromConn()
+		en, de, crypt, mux = s.GetConnInfoFromConn()
 		goto retry
 	}
 	cLen, err := s.GetLen()
@@ -245,13 +258,13 @@ func (s *Conn) WriteTo(b []byte, compress int, crypt bool) (n int, err error) {
 }
 
 //写压缩方式,加密
-func (s *Conn) WriteConnInfo(en, de int, crypt bool) {
-	s.Write([]byte(strconv.Itoa(en) + strconv.Itoa(de) + GetStrByBool(crypt)))
+func (s *Conn) WriteConnInfo(en, de int, crypt, mux bool) {
+	s.Write([]byte(strconv.Itoa(en) + strconv.Itoa(de) + GetStrByBool(crypt) + GetStrByBool(mux)))
 }
 
 //获取压缩方式,是否加密
-func (s *Conn) GetConnInfoFromConn() (en, de int, crypt bool) {
-	buf, err := s.ReadLen(3)
+func (s *Conn) GetConnInfoFromConn() (en, de int, crypt, mux bool) {
+	buf, err := s.ReadLen(4)
 	//TODO:错误处理
 	if err != nil {
 		return
@@ -259,6 +272,7 @@ func (s *Conn) GetConnInfoFromConn() (en, de int, crypt bool) {
 	en, _ = strconv.Atoi(string(buf[0]))
 	de, _ = strconv.Atoi(string(buf[1]))
 	crypt = GetBoolByStr(string(buf[2]))
+	mux = GetBoolByStr(string(buf[3]))
 	return
 }
 

+ 39 - 30
lib/file.go

@@ -10,18 +10,21 @@ import (
 	"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 ServerConfig struct {
+	TcpPort        int    //服务端与客户端通信端口
+	Mode           string //启动方式
+	Target         string //目标
+	VerifyKey      string //flag
+	U              string //socks5验证用户名
+	P              string //socks5验证密码
+	Compress       string //压缩方式
+	Start          int    //是否开启
+	IsRun          int    //是否在运行
+	ClientStatus   int    //客s户端状态
+	Crypt          bool   //是否加密
+	Mux            bool   //是否加密
+	CompressEncode int
+	CompressDecode int
 }
 
 type HostList struct {
@@ -39,7 +42,7 @@ func NewCsv(path string, bridge *Tunnel, runList map[string]interface{}) *Csv {
 }
 
 type Csv struct {
-	Tasks   []*TaskList
+	Tasks   []*ServerConfig
 	Path    string
 	Bridge  *Tunnel
 	RunList map[string]interface{}
@@ -69,7 +72,10 @@ func (s *Csv) StoreTasksToCsv() {
 			task.P,
 			task.Compress,
 			strconv.Itoa(task.Start),
-			task.Crypt,
+			GetStrByBool(task.Crypt),
+			GetStrByBool(task.Mux),
+			strconv.Itoa(task.CompressEncode),
+			strconv.Itoa(task.CompressDecode),
 		}
 		err := writer.Write(record)
 		if err != nil {
@@ -98,21 +104,24 @@ func (s *Csv) LoadTaskFromCsv() {
 	if err != nil {
 		panic(err)
 	}
-	var tasks []*TaskList
+	var tasks []*ServerConfig
 	// 将每一行数据保存到内存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],
+		post := &ServerConfig{
+			TcpPort:        tcpPort,
+			Mode:           item[1],
+			Target:         item[2],
+			VerifyKey:      item[3],
+			U:              item[4],
+			P:              item[5],
+			Compress:       item[6],
+			Start:          Start,
+			Crypt:          GetBoolByStr(item[8]),
+			Mux:            GetBoolByStr(item[9]),
+			CompressEncode: GetIntNoerrByStr(item[10]),
+			CompressDecode: GetIntNoerrByStr(item[11]),
 		}
 		tasks = append(tasks, post)
 	}
@@ -177,8 +186,8 @@ func (s *Csv) LoadHostFromCsv() {
 	s.Hosts = hosts
 }
 
-func (s *Csv) GetTaskList(start, length int, typeVal string) ([]*TaskList, int) {
-	list := make([]*TaskList, 0)
+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 {
@@ -209,12 +218,12 @@ func (s *Csv) GetTaskList(start, length int, typeVal string) ([]*TaskList, int)
 	return list, cnt
 }
 
-func (s *Csv) NewTask(t *TaskList) {
+func (s *Csv) NewTask(t *ServerConfig) {
 	s.Tasks = append(s.Tasks, t)
 	s.StoreTasksToCsv()
 }
 
-func (s *Csv) UpdateTask(t *TaskList) error {
+func (s *Csv) UpdateTask(t *ServerConfig) error {
 	for k, v := range s.Tasks {
 		if v.VerifyKey == t.VerifyKey {
 			s.Tasks = append(s.Tasks[:k], s.Tasks[k+1:]...)
@@ -246,7 +255,7 @@ func (s *Csv) DelTask(vKey string) error {
 	return errors.New("不存在")
 }
 
-func (s *Csv) GetTask(vKey string) (v *TaskList, err error) {
+func (s *Csv) GetTask(vKey string) (v *ServerConfig, err error) {
 	for _, v = range s.Tasks {
 		if v.VerifyKey == vKey {
 			return

+ 36 - 19
lib/init.go

@@ -16,11 +16,12 @@ var (
 	rpMode       = flag.String("mode", "client", "启动模式")
 	tunnelTarget = flag.String("target", "10.1.50.203:80", "远程目标")
 	verifyKey    = flag.String("vkey", "", "验证密钥")
-	u            = flag.String("u", "", "socks5验证用户名")
-	p            = flag.String("p", "", "socks5验证密码")
+	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", "", "是否加密(1|0)")
+	crypt        = flag.String("crypt", "false", "是否加密(true|false)")
+	mux          = flag.String("mux", "false", "是否TCP多路复用(true|false)")
 	config       Config
 	err          error
 	RunList      map[string]interface{} //运行中的任务
@@ -36,7 +37,6 @@ func init() {
 
 func InitMode() {
 	flag.Parse()
-	de, en := getCompressType(*compress)
 	if *rpMode == "client" {
 		JsonParse := NewJsonStruct()
 		if config, err = JsonParse.Load(*configPath); err != nil {
@@ -54,7 +54,25 @@ func InitMode() {
 			log.Fatalln("服务端开启失败", err)
 		}
 		log.Println("服务端启动,监听tcp服务端端口:", *TcpPort)
-		if svr := newMode(*rpMode, bridge, *httpPort, *tunnelTarget, *u, *p, en, de, *verifyKey, *crypt); svr != nil {
+		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("启动模式不正确")
@@ -73,26 +91,25 @@ func InitFromCsv() {
 	}
 }
 
-func newMode(mode string, bridge *Tunnel, httpPort int, tunnelTarget string, u string, p string, enCompress int, deCompress int, vkey string, crypt string) interface{} {
-	bCrypt := GetBoolByStr(crypt)
-	switch mode {
+func newMode(bridge *Tunnel, config *ServerConfig) interface{} {
+	switch config.Mode {
 	case "httpServer":
-		return NewHttpModeServer(httpPort, bridge, enCompress, deCompress, vkey, bCrypt)
+		return NewHttpModeServer(bridge, config)
 	case "tunnelServer":
-		return NewTunnelModeServer(httpPort, tunnelTarget, ProcessTunnel, bridge, enCompress, deCompress, vkey, u, p, bCrypt)
-	case "sock5Server":
-		return NewSock5ModeServer(httpPort, u, p, bridge, enCompress, deCompress, vkey, bCrypt)
+		return NewTunnelModeServer(ProcessTunnel, bridge, config)
+	case "socks5Server":
+		return NewSock5ModeServer(bridge, config)
 	case "httpProxyServer":
-		return NewTunnelModeServer(httpPort, tunnelTarget, ProcessHttp, bridge, enCompress, deCompress, vkey, u, p, bCrypt)
+		return NewTunnelModeServer(ProcessHttp, bridge, config)
 	case "udpServer":
-		return NewUdpModeServer(httpPort, tunnelTarget, bridge, enCompress, deCompress, vkey, bCrypt)
+		return NewUdpModeServer(bridge, config)
 	case "webServer":
 		InitCsvDb()
 		return NewWebServer(bridge)
 	case "hostServer":
-		return NewHostServer(bCrypt)
+		return NewHostServer(config)
 	case "httpHostServer":
-		return NewTunnelModeServer(httpPort, tunnelTarget, ProcessHost, bridge, enCompress, deCompress, vkey, u, p, bCrypt)
+		return NewTunnelModeServer(ProcessHost, bridge, config)
 	}
 	return nil
 }
@@ -116,9 +133,9 @@ func StopServer(cFlag string) error {
 	return errors.New("未在运行中")
 }
 
-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, t.Crypt); svr != nil {
+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]

+ 21 - 28
lib/socks5.go

@@ -44,16 +44,10 @@ const (
 )
 
 type Sock5ModeServer struct {
-	bridge     *Tunnel
-	httpPort   int
-	u          string //用户名
-	p          string //密码
-	enCompress int
-	deCompress int
-	isVerify   bool
-	listener   net.Listener
-	vKey       string
-	crypt      bool
+	bridge   *Tunnel
+	isVerify bool
+	listener net.Listener
+	config   *ServerConfig
 }
 
 //req
@@ -140,10 +134,9 @@ 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, s.crypt)
+	client, err := s.bridge.GetTunnel(getverifyval(s.config.VerifyKey), s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
 	if err != nil {
 		log.Println(err)
-		client.Close()
 		return
 	}
 	s.sendReply(c, succeeded)
@@ -164,8 +157,11 @@ func (s *Sock5ModeServer) handleConnect(c net.Conn) {
 		log.Println(err)
 		c.Close()
 	} else {
-		go relay(proxyConn, NewConn(c), s.enCompress, s.crypt)
-		go relay(NewConn(c), proxyConn, s.deCompress, s.crypt)
+		go relay(proxyConn, NewConn(c), s.config.CompressEncode, s.config.Crypt, s.config.Mux)
+		relay(NewConn(c), proxyConn, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
+		if s.config.Mux {
+			s.bridge.ReturnTunnel(proxyConn, getverifyval(s.config.VerifyKey))
+		}
 	}
 
 }
@@ -198,8 +194,11 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) {
 	if err != nil {
 		c.Close()
 	} else {
-		go relay(proxyConn, NewConn(c), s.enCompress, s.crypt)
-		go relay(NewConn(c), proxyConn, s.deCompress, s.crypt)
+		go relay(proxyConn, NewConn(c), s.config.CompressEncode, s.config.Crypt, s.config.Mux)
+		relay(NewConn(c), proxyConn, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
+		if s.config.Mux {
+			s.bridge.ReturnTunnel(proxyConn, getverifyval(s.config.VerifyKey))
+		}
 	}
 }
 
@@ -262,7 +261,7 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error {
 	if _, err := io.ReadAtLeast(c, pass, passLen); err != nil {
 		return err
 	}
-	if string(pass) == s.p && string(user) == s.u {
+	if string(pass) == s.config.U && string(user) == s.config.P {
 		if _, err := c.Write([]byte{userAuthVersion, authSuccess}); err != nil {
 			return err
 		}
@@ -278,7 +277,7 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error {
 
 //start
 func (s *Sock5ModeServer) Start() error {
-	s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.httpPort))
+	s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.config.TcpPort))
 	if err != nil {
 		return err
 	}
@@ -301,20 +300,14 @@ func (s *Sock5ModeServer) Close() error {
 }
 
 //new
-func NewSock5ModeServer(httpPort int, u, p string, brige *Tunnel, enCompress int, deCompress int, vKey string, crypt bool) *Sock5ModeServer {
+func NewSock5ModeServer(bridge *Tunnel, cnf *ServerConfig) *Sock5ModeServer {
 	s := new(Sock5ModeServer)
-	s.httpPort = httpPort
-	s.bridge = brige
-	if u != "" && p != "" {
+	s.bridge = bridge
+	s.config = cnf
+	if s.config.U != "" && s.config.P != "" {
 		s.isVerify = true
-		s.u = u
-		s.p = p
 	} else {
 		s.isVerify = false
 	}
-	s.enCompress = enCompress
-	s.deCompress = deCompress
-	s.vKey = vKey
-	s.crypt = crypt
 	return s
 }

+ 38 - 55
lib/server.go → lib/tcp.go

@@ -33,23 +33,15 @@ WWW-Authenticate: Basic realm="easyProxy"
 type process func(c *Conn, s *TunnelModeServer) error
 
 type HttpModeServer struct {
-	bridge     *Tunnel
-	httpPort   int
-	enCompress int
-	deCompress int
-	vKey       string
-	crypt      bool
+	bridge *Tunnel
+	config *ServerConfig
 }
 
 //http
-func NewHttpModeServer(httpPort int, bridge *Tunnel, enCompress int, deCompress int, vKey string, crypt bool) *HttpModeServer {
+func NewHttpModeServer(bridge *Tunnel, cnf *ServerConfig) *HttpModeServer {
 	s := new(HttpModeServer)
 	s.bridge = bridge
-	s.httpPort = httpPort
-	s.enCompress = enCompress
-	s.deCompress = deCompress
-	s.vKey = vKey
-	s.crypt = crypt
+	s.config = cnf
 	return s
 }
 
@@ -65,7 +57,7 @@ func (s *HttpModeServer) Start() {
 			w.Write([]byte("401 Unauthorized\n"))
 			return
 		}
-		err, conn := s.bridge.GetSignal(getverifyval(s.vKey))
+		err, conn := s.bridge.GetSignal(getverifyval(s.config.VerifyKey))
 		if err != nil {
 			BadRequest(w)
 			return
@@ -83,9 +75,9 @@ func (s *HttpModeServer) Start() {
 			goto retry
 			return
 		}
-		s.bridge.ReturnSignal(conn, getverifyval(s.vKey))
+		s.bridge.ReturnSignal(conn, getverifyval(s.config.VerifyKey))
 	})
-	log.Fatalln(http.ListenAndServe(fmt.Sprintf(":%d", s.httpPort), nil))
+	log.Fatalln(http.ListenAndServe(fmt.Sprintf(":%d", s.config.TcpPort), nil))
 }
 
 //req转为bytes发送给client端
@@ -95,8 +87,8 @@ func (s *HttpModeServer) writeRequest(r *http.Request, conn *Conn) error {
 		return err
 	}
 	conn.wSign()
-	conn.WriteConnInfo(s.enCompress, s.deCompress, s.crypt)
-	c, err := conn.WriteTo(raw, s.enCompress, s.crypt)
+	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
 	}
@@ -115,7 +107,7 @@ func (s *HttpModeServer) writeResponse(w http.ResponseWriter, c *Conn) error {
 	switch flags {
 	case RES_SIGN:
 		buf := make([]byte, 1024*1024*32)
-		n, err := c.ReadFrom(buf, s.deCompress, s.crypt)
+		n, err := c.ReadFrom(buf, s.config.CompressDecode, s.config.Crypt)
 		if err != nil {
 			return err
 		}
@@ -145,38 +137,24 @@ func (s *HttpModeServer) writeResponse(w http.ResponseWriter, c *Conn) error {
 }
 
 type TunnelModeServer struct {
-	httpPort      int
-	tunnelTarget  string
-	process       process
-	bridge        *Tunnel
-	listener      *net.TCPListener
-	enCompress    int
-	deCompress    int
-	basicUser     string
-	basicPassword string
-	vKey          string
-	crypt         bool
+	process  process
+	bridge   *Tunnel
+	config   *ServerConfig
+	listener *net.TCPListener
 }
 
 //tcp|http|host
-func NewTunnelModeServer(httpPort int, tunnelTarget string, process process, bridge *Tunnel, enCompress, deCompress int, vKey, basicUser, basicPasswd string, crypt bool) *TunnelModeServer {
+func NewTunnelModeServer(process process, bridge *Tunnel, cnf *ServerConfig) *TunnelModeServer {
 	s := new(TunnelModeServer)
-	s.httpPort = httpPort
 	s.bridge = bridge
-	s.tunnelTarget = tunnelTarget
 	s.process = process
-	s.enCompress = enCompress
-	s.deCompress = deCompress
-	s.vKey = vKey
-	s.basicUser = basicUser
-	s.basicPassword = basicPasswd
-	s.crypt = crypt
+	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.httpPort, ""})
+	s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.config.TcpPort, ""})
 	if err != nil {
 		return err
 	}
@@ -205,14 +183,19 @@ func (s *TunnelModeServer) auth(r *http.Request, c *Conn, u, p string) error {
 }
 
 //与客户端建立通道
-func (s *TunnelModeServer) dealClient(vKey string, en, de int, c *Conn, target string, method string, rb []byte) error {
-	link, err := s.bridge.GetTunnel(getverifyval(vKey), en, de, s.crypt)
+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))
+		}
+	}()
 	if err != nil {
 		log.Println(err)
 		c.Close()
 		return err
 	}
-	if _, err := link.WriteHost(CONN_TCP, target); err != nil {
+	if _, err := link.WriteHost(CONN_TCP, addr); err != nil {
 		c.Close()
 		link.Close()
 		log.Println(err)
@@ -221,10 +204,10 @@ func (s *TunnelModeServer) dealClient(vKey string, en, de int, c *Conn, target s
 	if method == "CONNECT" {
 		fmt.Fprint(c, "HTTP/1.1 200 Connection established\r\n")
 	} else {
-		link.WriteTo(rb, en, s.crypt)
+		link.WriteTo(rb, cnf.CompressEncode, cnf.Crypt)
 	}
-	go relay(link, c, en, s.crypt)
-	relay(c, link, de, s.crypt)
+	go relay(link, c, cnf.CompressEncode, cnf.Crypt, cnf.Mux)
+	relay(c, link, cnf.CompressDecode, cnf.Crypt, cnf.Mux)
 	return nil
 }
 
@@ -237,11 +220,11 @@ func (s *TunnelModeServer) Close() error {
 func ProcessTunnel(c *Conn, s *TunnelModeServer) error {
 	method, _, rb, err, r := c.GetHost()
 	if err == nil {
-		if err := s.auth(r, c, s.basicUser, s.basicPassword); err != nil {
+		if err := s.auth(r, c, s.config.U, s.config.P); err != nil {
 			return err
 		}
 	}
-	return s.dealClient(s.vKey, s.enCompress, s.deCompress, c, s.tunnelTarget, method, rb)
+	return s.dealClient(c, s.config, s.config.Target, method, rb)
 }
 
 //http代理模式
@@ -251,10 +234,11 @@ func ProcessHttp(c *Conn, s *TunnelModeServer) error {
 		c.Close()
 		return err
 	}
-	if err := s.auth(r, c, s.basicUser, s.basicPassword); err != nil {
+	if err := s.auth(r, c, s.config.U, s.config.P); err != nil {
 		return err
 	}
-	return s.dealClient(s.vKey, s.enCompress, s.deCompress, c, addr, method, rb)
+	//TODO效率问题
+	return s.dealClient(c, s.config, addr, method, rb)
 }
 
 //多客户端域名代理
@@ -272,8 +256,7 @@ func ProcessHost(c *Conn, s *TunnelModeServer) error {
 		c.Close()
 		return err
 	}
-	de, en := getCompressType(task.Compress)
-	return s.dealClient(host.Vkey, en, de, c, host.Target, method, rb)
+	return s.dealClient(c, task, host.Target, method, rb)
 }
 
 //web管理方式
@@ -285,7 +268,7 @@ type WebServer struct {
 func (s *WebServer) Start() {
 	InitFromCsv()
 	p, _ := beego.AppConfig.Int("hostPort")
-	t := &TaskList{
+	t := &ServerConfig{
 		TcpPort:      p,
 		Mode:         "httpHostServer",
 		Target:       "",
@@ -312,7 +295,7 @@ func NewWebServer(bridge *Tunnel) *WebServer {
 
 //host
 type HostServer struct {
-	crypt bool
+	config *ServerConfig
 }
 
 //开始
@@ -321,9 +304,9 @@ func (s *HostServer) Start() error {
 }
 
 //TODO:host模式的客户端,无需指定和监听端口等
-func NewHostServer(crypt bool) *HostServer {
+func NewHostServer(cnf *ServerConfig) *HostServer {
 	s := new(HostServer)
-	s.crypt = crypt
+	s.config = cnf
 	return s
 }
 

+ 16 - 21
lib/udp.go

@@ -9,33 +9,23 @@ import (
 )
 
 type UdpModeServer struct {
-	bridge       *Tunnel
-	udpPort      int    //监听的udp端口
-	tunnelTarget string //udp目标地址
-	listener     *net.UDPConn
-	udpMap       map[string]*Conn
-	enCompress   int
-	deCompress   int
-	vKey         string
-	crypt        bool
+	bridge   *Tunnel
+	listener *net.UDPConn
+	udpMap   map[string]*Conn
+	config   *ServerConfig
 }
 
-func NewUdpModeServer(udpPort int, tunnelTarget string, bridge *Tunnel, enCompress int, deCompress int, vKey string, crypt bool) *UdpModeServer {
+func NewUdpModeServer(bridge *Tunnel, cnf *ServerConfig) *UdpModeServer {
 	s := new(UdpModeServer)
-	s.udpPort = udpPort
-	s.tunnelTarget = tunnelTarget
 	s.bridge = bridge
 	s.udpMap = make(map[string]*Conn)
-	s.enCompress = enCompress
-	s.deCompress = deCompress
-	s.vKey = vKey
-	s.crypt = crypt
+	s.config = cnf
 	return s
 }
 
 //开始
 func (s *UdpModeServer) Start() error {
-	s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.udpPort, ""})
+	s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.config.TcpPort, ""})
 	if err != nil {
 		return err
 	}
@@ -55,20 +45,25 @@ func (s *UdpModeServer) Start() error {
 
 //TODO:效率问题有待解决
 func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
-	conn, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress, s.crypt)
+	conn, err := s.bridge.GetTunnel(getverifyval(s.config.VerifyKey), s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
 	if err != nil {
 		log.Println(err)
 		return
 	}
-	if _, err := conn.WriteHost(CONN_UDP, s.tunnelTarget); err != nil {
+	if _, err := conn.WriteHost(CONN_UDP, s.config.Target); err != nil {
 		conn.Close()
 		return
 	}
-	conn.WriteTo(data, s.enCompress,s.crypt)
+	conn.WriteTo(data, s.config.CompressEncode, s.config.Crypt)
 	go func(addr *net.UDPAddr, conn *Conn) {
+		defer func() {
+			if s.config.Mux {
+				s.bridge.ReturnTunnel(conn, getverifyval(s.config.VerifyKey))
+			}
+		}()
 		buf := make([]byte, 1024)
 		conn.conn.SetReadDeadline(time.Now().Add(time.Duration(time.Second * 3)))
-		n, err := conn.ReadFrom(buf, s.deCompress,s.crypt)
+		n, err := conn.ReadFrom(buf, s.config.CompressDecode, s.config.Crypt)
 		if err != nil || err == io.EOF {
 			conn.Close()
 			return

+ 25 - 4
lib/util.go

@@ -27,6 +27,7 @@ const (
 	COMPRESS_NONE_DECODE
 	COMPRESS_SNAPY_ENCODE
 	COMPRESS_SNAPY_DECODE
+	IO_EOF = "EOF"
 )
 
 //error
@@ -130,19 +131,35 @@ func replaceHost(resp []byte) []byte {
 }
 
 //copy
-func relay(in, out *Conn, compressType int, crypt bool) {
+func relay(in, out *Conn, compressType int, crypt, mux bool) {
 	switch compressType {
 	case COMPRESS_SNAPY_ENCODE:
 		copyBuffer(NewSnappyConn(in.conn, crypt), out)
+		if mux {
+			NewSnappyConn(in.conn, crypt).Write([]byte(IO_EOF))
+			out.Close()
+		}
 	case COMPRESS_SNAPY_DECODE:
 		copyBuffer(in, NewSnappyConn(out.conn, crypt))
+		if mux {
+			in.Close()
+		}
 	case COMPRESS_NONE_ENCODE:
 		copyBuffer(NewCryptConn(in.conn, crypt), out)
+		if mux {
+			NewCryptConn(in.conn, crypt).Write([]byte(IO_EOF))
+			out.Close()
+		}
 	case COMPRESS_NONE_DECODE:
 		copyBuffer(in, NewCryptConn(out.conn, crypt))
+		if mux {
+			in.Close()
+		}
+	}
+	if !mux {
+		in.Close()
+		out.Close()
 	}
-	out.Close()
-	in.Close()
 }
 
 //判断压缩方式
@@ -183,7 +200,7 @@ func verify(verifyKeyMd5 string) bool {
 }
 
 //get key by host from x
-func getKeyByHost(host string) (h *HostList, t *TaskList, err error) {
+func getKeyByHost(host string) (h *HostList, t *ServerConfig, err error) {
 	for _, v := range CsvDb.Hosts {
 		if strings.Contains(host, v.Host) {
 			h = v
@@ -258,6 +275,10 @@ func GetStrByBool(b bool) string {
 	}
 	return "0"
 }
+func GetIntNoerrByStr(str string) int {
+	i, _ := strconv.Atoi(str)
+	return i
+}
 
 // io.copy的优化版,读取buffer长度原为32*1024,与snappy不同,导致读取出的内容存在差异,不利于解密,特此修改
 func copyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {

+ 7 - 0
views/index/add.html

@@ -44,6 +44,13 @@
                             <option value="1">加密</option>
                         </select>
                     </div>
+                    <div class="form-group" id="compress">
+                        <label class="control-label">是否TCP复用</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,web穿透支持)</label>
                         <input class="form-control" type="text" name="u" placeholder="不填则无需验证">

+ 9 - 2
views/index/edit.html

@@ -35,8 +35,15 @@
                     <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>
+                            <option {{if eq false .t.Crypt}}selected{{end}} value="0">不加密</option>
+                            <option {{if eq  true .t.Crypt}}selected{{end}} value="1">加密</option>
+                        </select>
+                    </div>
+                    <div class="form-group" id="compress">
+                        <label class="control-label">是否启用TCP复用(所有模式均支持)</label>
+                        <select class="form-control" name="mux">
+                            <option {{if eq false .t.Mux}}selected{{end}} value="0">不启用</option>
+                            <option {{if eq  true .t.Mux}}selected{{end}} value="1">启用</option>
                         </select>
                     </div>
                     <div class="form-group" id="u">

+ 15 - 2
views/index/list.html

@@ -11,6 +11,7 @@
                         <th>多客户端模式客户端执行命令</th>
                         <th>压缩方式</th>
                         <th>加密传输</th>
+                        <th>TCP多路复用</th>
                         <th>用户名</th>
                         <th>密码</th>
                         <th>客户端状态</th>
@@ -97,7 +98,7 @@
             autoWidth: false,
             ordering: false,
             ajax: {
-                url: '/index/gettasklist?type={{.type}}',
+                url: '/index/getserverconfig?type={{.type}}',
                 type: 'POST'
             },
             dom: '<"top"fl><"toolbar">rt<"bottom"ip><"clear">',
@@ -108,6 +109,7 @@
                 {data: 'VerifyKey'},
                 {data: 'Compress'},
                 {data: 'Crypt'},
+                {data: 'Mux'},
                 {data: 'U'},
                 {data: 'P'},
                 {data: 'ClientStatus'},
@@ -149,7 +151,7 @@
                     }
                 },
                 {
-                    targets: -6,
+                    targets: -7,
                     render: function (data, type, row, meta) {
                         if (data == "0") {
                             return "不加密"
@@ -158,6 +160,17 @@
                         }
                     }
                 },
+                {
+                    targets: -6,
+                    render: function (data, type, row, meta) {
+                        if (data == "0") {
+                            return "不启用"
+                        } else {
+                            return "启用"
+                        }
+                    }
+                }
+                ,
                 {
                     targets: 2,
                     render: function (data, type, row, meta) {