From 9bec5366a643f5f47ed635c0784778b66c334996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B2=B3?= Date: Sun, 6 Jan 2019 03:16:46 +0800 Subject: [PATCH] =?UTF-8?q?Tcp=E5=A4=9A=E8=B7=AF=E5=A4=8D=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf/tasks.csv | 6 +-- controllers/index.go | 12 +++-- lib/{tunnel.go => bridge.go} | 15 ++++-- lib/client.go | 30 +++++++++--- lib/conn.go | 28 ++++++++--- lib/file.go | 69 ++++++++++++++------------ lib/init.go | 55 +++++++++++++-------- lib/socks5.go | 49 ++++++++----------- lib/{server.go => tcp.go} | 93 +++++++++++++++--------------------- lib/udp.go | 37 +++++++------- lib/util.go | 29 +++++++++-- views/index/add.html | 7 +++ views/index/edit.html | 11 ++++- views/index/list.html | 17 ++++++- 14 files changed, 271 insertions(+), 187 deletions(-) rename lib/{tunnel.go => bridge.go} (91%) rename lib/{server.go => tcp.go} (70%) diff --git a/conf/tasks.csv b/conf/tasks.csv index 19ba826..8c3e4e7 100644 --- a/conf/tasks.csv +++ b/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 diff --git a/controllers/index.go b/controllers/index.go index 903c630..a6fce5d 100755 --- a/controllers/index.go +++ b/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) diff --git a/lib/tunnel.go b/lib/bridge.go similarity index 91% rename from lib/tunnel.go rename to lib/bridge.go index 959805e..79f4366 100755 --- a/lib/tunnel.go +++ b/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) diff --git a/lib/client.go b/lib/client.go index 95216c6..ac95869 100755 --- a/lib/client.go +++ b/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() diff --git a/lib/conn.go b/lib/conn.go index 008f67d..b3f1c5e 100755 --- a/lib/conn.go +++ b/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 } diff --git a/lib/file.go b/lib/file.go index 82448f8..a6a6a25 100644 --- a/lib/file.go +++ b/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 diff --git a/lib/init.go b/lib/init.go index 3511e1d..3818502 100644 --- a/lib/init.go +++ b/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] diff --git a/lib/socks5.go b/lib/socks5.go index ad6db6f..963441e 100755 --- a/lib/socks5.go +++ b/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 } diff --git a/lib/server.go b/lib/tcp.go similarity index 70% rename from lib/server.go rename to lib/tcp.go index 01153ad..3631b5d 100755 --- a/lib/server.go +++ b/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 } diff --git a/lib/udp.go b/lib/udp.go index 97f462b..2405b25 100755 --- a/lib/udp.go +++ b/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 diff --git a/lib/util.go b/lib/util.go index 675d1a6..17a0916 100755 --- a/lib/util.go +++ b/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) { diff --git a/views/index/add.html b/views/index/add.html index 4da2817..1ba6341 100755 --- a/views/index/add.html +++ b/views/index/add.html @@ -44,6 +44,13 @@ +
+ + +
diff --git a/views/index/edit.html b/views/index/edit.html index bcdab66..34e561d 100755 --- a/views/index/edit.html +++ b/views/index/edit.html @@ -35,8 +35,15 @@
+
+
+ +
diff --git a/views/index/list.html b/views/index/list.html index 15c1374..38b6b02 100755 --- a/views/index/list.html +++ b/views/index/list.html @@ -11,6 +11,7 @@ 多客户端模式客户端执行命令 压缩方式 加密传输 + TCP多路复用 用户名 密码 客户端状态 @@ -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) {