From 5700101c0e9093e1bba5477f6b7d12c08c43eeab Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 17 Mar 2016 11:04:40 +0800 Subject: [PATCH 01/14] doc: typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 26d83a8f..1c204d13 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## What is frp? -frp is a fast reverse proxy which can help you expose a local server behind a NAT or firewall to the internet. +frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet. ## Status From 931c102668150aa7990bd2a3d9bcdeb26d4f1b7a Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 17 Mar 2016 17:47:41 +0800 Subject: [PATCH 02/14] fix bug in Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index bbfc6e13..8226cb3f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,4 +11,4 @@ RUN cd /usr/share/frp && make EXPOSE 80 EXPOSE 7000 -CMD ["/usr/share/frp/bin/frps -c /usr/share/frps.ini"] +CMD ["/usr/share/frp/bin/frps", "-c", "/usr/share/frps.ini"] From 6e5713553389c469f9a6b9c2db1cdc46875d5141 Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 17 Mar 2016 17:52:59 +0800 Subject: [PATCH 03/14] typo --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8226cb3f..5480f421 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM golang:1.5 MAINTAINER fatedier -RUN echo "[common]\nbind_addr = 0.0.0.0\nbind_port = 7000\n[wiki]\npasswd = 123\nbind_addr = 0.0.0.0\nlisten_port = 80" > /usr/share/frps.ini +RUN echo "[common]\nbind_addr = 0.0.0.0\nbind_port = 7000\n[test]\npasswd = 123\nbind_addr = 0.0.0.0\nlisten_port = 80" > /usr/share/frps.ini ADD ./ /usr/share/frp/ From 20afe25ef12713fbedef5c904a885f75f8235fcc Mon Sep 17 00:00:00 2001 From: Gogs Date: Tue, 22 Mar 2016 17:18:05 +0800 Subject: [PATCH 04/14] modified: src/frp/models/client/client.go modified: src/frp/models/server/server.go modified: src/frp/utils/conn/conn.go modified: src/frp/utils/pcrypto/pcrypto.go modified: src/frp/utils/pcrypto/pcrypto_test.go --- conf/frpc.ini | 2 +- src/frp/models/client/client.go | 5 +- src/frp/models/server/server.go | 4 +- src/frp/utils/conn/conn.go | 73 +++++++++++++++++++++++++++ src/frp/utils/pcrypto/pcrypto.go | 10 ++-- src/frp/utils/pcrypto/pcrypto_test.go | 14 ----- 6 files changed, 86 insertions(+), 22 deletions(-) diff --git a/conf/frpc.ini b/conf/frpc.ini index 09dfeb75..c5dbb49c 100644 --- a/conf/frpc.ini +++ b/conf/frpc.ini @@ -11,4 +11,4 @@ log_level = debug [test1] passwd = 123 local_ip = 127.0.0.1 -local_port = 22 +local_port = 8000 diff --git a/src/frp/models/client/client.go b/src/frp/models/client/client.go index ce99f098..8ee36ca3 100644 --- a/src/frp/models/client/client.go +++ b/src/frp/models/client/client.go @@ -81,6 +81,9 @@ func (p *ProxyClient) StartTunnel(serverAddr string, serverPort int64) (err erro // l means local, r means remote log.Debug("Join two conns, (l[%s] r[%s]) (l[%s] r[%s])", localConn.GetLocalAddr(), localConn.GetRemoteAddr(), remoteConn.GetLocalAddr(), remoteConn.GetRemoteAddr()) - go conn.Join(localConn, remoteConn) + // go conn.Join(localConn, remoteConn) + go conn.PipeEncryptoWriter(localConn.TcpConn, remoteConn.TcpConn, p.Passwd) + go conn.PipeDecryptoReader(remoteConn.TcpConn, localConn.TcpConn, p.Passwd) + return nil } diff --git a/src/frp/models/server/server.go b/src/frp/models/server/server.go index 0b2c3d49..eb39529e 100644 --- a/src/frp/models/server/server.go +++ b/src/frp/models/server/server.go @@ -132,7 +132,9 @@ func (p *ProxyServer) Start() (err error) { // l means local, r means remote log.Debug("Join two conns, (l[%s] r[%s]) (l[%s] r[%s])", cliConn.GetLocalAddr(), cliConn.GetRemoteAddr(), userConn.GetLocalAddr(), userConn.GetRemoteAddr()) - go conn.Join(cliConn, userConn) + // go conn.Join(cliConn, userConn) + go conn.PipeEncryptoWriter(userConn.TcpConn, cliConn.TcpConn, p.Passwd) + go conn.PipeDecryptoReader(cliConn.TcpConn, userConn.TcpConn, p.Passwd) } }() diff --git a/src/frp/utils/conn/conn.go b/src/frp/utils/conn/conn.go index fbf4be99..68cf6536 100644 --- a/src/frp/utils/conn/conn.go +++ b/src/frp/utils/conn/conn.go @@ -22,6 +22,7 @@ import ( "sync" "frp/utils/log" + "frp/utils/pcrypto" ) type Listener struct { @@ -127,6 +128,7 @@ func (c *Conn) ReadLine() (buff string, err error) { func (c *Conn) Write(content string) (err error) { _, err = c.TcpConn.Write([]byte(content)) return err + } func (c *Conn) Close() { @@ -161,3 +163,74 @@ func Join(c1 *Conn, c2 *Conn) { wait.Wait() return } + +// decrypto msg from reader, then write into writer +func PipeDecryptoReader(r net.Conn, w net.Conn, key string) { + defer r.Close() + defer w.Close() + + laes := new(pcrypto.Pcrypto) + if err := laes.Init([]byte(key)); err != nil { + log.Error("Pcrypto Init error, [%v]", err) + return + } + + log.Debug("PipeDecryptoReader") + + buf := make([]byte, 10*1024) + + for { + n, err := r.Read(buf) + if err != nil { + log.Error("Conn ReadLine error, [%v]", err) + return + } + + res, err := laes.Decrypto(buf[:n]) + if err != nil { + log.Error("Decrypto error, [%s] [%s]", err, string(buf[:n])) + return + } + + _, err = w.Write(res) + if err != nil { + log.Error("net.Conn Write error, [%v]", err) + return + } + } +} + +// recvive msg from reader, then encrypto msg into write +func PipeEncryptoWriter(r net.Conn, w net.Conn, key string) { + defer r.Close() + defer w.Close() + + laes := new(pcrypto.Pcrypto) + if err := laes.Init([]byte(key)); err != nil { + log.Error("Pcrypto Init error, [%v]", err) + return + } + + log.Debug("PipeEncryptoWriter") + + buf := make([]byte, 10*1024) + + for { + n, err := r.Read(buf) + if err != nil { + log.Error("Conn ReadLine error, [%v]", err) + return + } + res, err := laes.Encrypto(buf[:n]) + if err != nil { + log.Error("Encrypto error, [%v]", err) + return + } + + _, err = w.Write(res) + if err != nil { + log.Error("net.Conn Write error, [%v]", err) + return + } + } +} diff --git a/src/frp/utils/pcrypto/pcrypto.go b/src/frp/utils/pcrypto/pcrypto.go index e260a3e9..8a4435e2 100644 --- a/src/frp/utils/pcrypto/pcrypto.go +++ b/src/frp/utils/pcrypto/pcrypto.go @@ -33,7 +33,7 @@ type Pcrypto struct { func (pc *Pcrypto) Init(key []byte) error { var err error - pc.pkey = PKCS7Padding(key, aes.BlockSize) + pc.pkey = pKCS7Padding(key, aes.BlockSize) pc.paes, err = aes.NewCipher(pc.pkey) return err @@ -41,7 +41,7 @@ func (pc *Pcrypto) Init(key []byte) error { func (pc *Pcrypto) Encrypto(src []byte) ([]byte, error) { // aes - src = PKCS7Padding(src, aes.BlockSize) + src = pKCS7Padding(src, aes.BlockSize) blockMode := cipher.NewCBCEncrypter(pc.paes, pc.pkey) crypted := make([]byte, len(src)) blockMode.CryptBlocks(crypted, src) @@ -83,18 +83,18 @@ func (pc *Pcrypto) Decrypto(str []byte) ([]byte, error) { blockMode := cipher.NewCBCDecrypter(pc.paes, pc.pkey) blockMode.CryptBlocks(decryptText, decryptText) - decryptText = PKCS7UnPadding(decryptText) + decryptText = pKCS7UnPadding(decryptText) return decryptText, nil } -func PKCS7Padding(ciphertext []byte, blockSize int) []byte { +func pKCS7Padding(ciphertext []byte, blockSize int) []byte { padding := blockSize - len(ciphertext)%blockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) } -func PKCS7UnPadding(origData []byte) []byte { +func pKCS7UnPadding(origData []byte) []byte { length := len(origData) unpadding := int(origData[length-1]) return origData[:(length - unpadding)] diff --git a/src/frp/utils/pcrypto/pcrypto_test.go b/src/frp/utils/pcrypto/pcrypto_test.go index 43e38f0c..016dd529 100644 --- a/src/frp/utils/pcrypto/pcrypto_test.go +++ b/src/frp/utils/pcrypto/pcrypto_test.go @@ -15,7 +15,6 @@ package pcrypto import ( - "crypto/aes" "fmt" "testing" ) @@ -46,16 +45,3 @@ func TestDecrypto(t *testing.T) { fmt.Printf("[%s]\n", string(res)) } - -func TestPKCS7Padding(t *testing.T) { - ltt := []byte("Test_PKCS7Padding") - ltt = PKCS7Padding(ltt, aes.BlockSize) - // fmt.Printf("[%x]\n", (ltt)) -} - -func TestPKCS7UnPadding(t *testing.T) { - ltt := []byte("Test_PKCS7Padding") - ltt = PKCS7Padding(ltt, aes.BlockSize) - ltt = PKCS7UnPadding(ltt) - // fmt.Printf("[%x]\n", ltt) -} From 49975c4c1b5651a9e49e088d8e854184b46e27a9 Mon Sep 17 00:00:00 2001 From: Gogs Date: Thu, 24 Mar 2016 15:37:40 +0800 Subject: [PATCH 05/14] fix crypto --- src/frp/utils/conn/conn.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/frp/utils/conn/conn.go b/src/frp/utils/conn/conn.go index 68cf6536..2b5cb7dd 100644 --- a/src/frp/utils/conn/conn.go +++ b/src/frp/utils/conn/conn.go @@ -175,20 +175,18 @@ func PipeDecryptoReader(r net.Conn, w net.Conn, key string) { return } - log.Debug("PipeDecryptoReader") - - buf := make([]byte, 10*1024) + nreader := bufio.NewReader(r) for { - n, err := r.Read(buf) + buf, err := nreader.ReadBytes('\n') if err != nil { - log.Error("Conn ReadLine error, [%v]", err) + log.Error("Conn ReadBytes error, [%v]", err) return } - res, err := laes.Decrypto(buf[:n]) + res, err := laes.Decrypto(buf) if err != nil { - log.Error("Decrypto error, [%s] [%s]", err, string(buf[:n])) + log.Error("Decrypto error, [%s] [%s]", err, string(buf)) return } @@ -211,12 +209,11 @@ func PipeEncryptoWriter(r net.Conn, w net.Conn, key string) { return } - log.Debug("PipeEncryptoWriter") - + nreader := bufio.NewReader(r) buf := make([]byte, 10*1024) for { - n, err := r.Read(buf) + n, err := nreader.Read(buf) if err != nil { log.Error("Conn ReadLine error, [%v]", err) return @@ -227,6 +224,7 @@ func PipeEncryptoWriter(r net.Conn, w net.Conn, key string) { return } + res = append(res, '\n') _, err = w.Write(res) if err != nil { log.Error("net.Conn Write error, [%v]", err) From 45c21b2705d51502aa5d26404d0b7982752dae95 Mon Sep 17 00:00:00 2001 From: fatedier Date: Mon, 28 Mar 2016 11:22:36 +0800 Subject: [PATCH 06/14] utils/conn: add func joinMore --- conf/frpc.ini | 2 +- src/frp/models/client/client.go | 3 +- src/frp/models/server/server.go | 3 +- src/frp/utils/conn/conn.go | 72 +++++++++++++++++++++------------ 4 files changed, 50 insertions(+), 30 deletions(-) diff --git a/conf/frpc.ini b/conf/frpc.ini index c5dbb49c..09dfeb75 100644 --- a/conf/frpc.ini +++ b/conf/frpc.ini @@ -11,4 +11,4 @@ log_level = debug [test1] passwd = 123 local_ip = 127.0.0.1 -local_port = 8000 +local_port = 22 diff --git a/src/frp/models/client/client.go b/src/frp/models/client/client.go index 8ee36ca3..6b85a17b 100644 --- a/src/frp/models/client/client.go +++ b/src/frp/models/client/client.go @@ -82,8 +82,7 @@ func (p *ProxyClient) StartTunnel(serverAddr string, serverPort int64) (err erro log.Debug("Join two conns, (l[%s] r[%s]) (l[%s] r[%s])", localConn.GetLocalAddr(), localConn.GetRemoteAddr(), remoteConn.GetLocalAddr(), remoteConn.GetRemoteAddr()) // go conn.Join(localConn, remoteConn) - go conn.PipeEncryptoWriter(localConn.TcpConn, remoteConn.TcpConn, p.Passwd) - go conn.PipeDecryptoReader(remoteConn.TcpConn, localConn.TcpConn, p.Passwd) + go conn.JoinMore(localConn, remoteConn, p.Passwd) return nil } diff --git a/src/frp/models/server/server.go b/src/frp/models/server/server.go index eb39529e..f59bcdcb 100644 --- a/src/frp/models/server/server.go +++ b/src/frp/models/server/server.go @@ -133,8 +133,7 @@ func (p *ProxyServer) Start() (err error) { log.Debug("Join two conns, (l[%s] r[%s]) (l[%s] r[%s])", cliConn.GetLocalAddr(), cliConn.GetRemoteAddr(), userConn.GetLocalAddr(), userConn.GetRemoteAddr()) // go conn.Join(cliConn, userConn) - go conn.PipeEncryptoWriter(userConn.TcpConn, cliConn.TcpConn, p.Passwd) - go conn.PipeDecryptoReader(cliConn.TcpConn, userConn.TcpConn, p.Passwd) + go conn.JoinMore(userConn, cliConn, p.Passwd) } }() diff --git a/src/frp/utils/conn/conn.go b/src/frp/utils/conn/conn.go index 2b5cb7dd..b3738bdc 100644 --- a/src/frp/utils/conn/conn.go +++ b/src/frp/utils/conn/conn.go @@ -164,49 +164,72 @@ func Join(c1 *Conn, c2 *Conn) { return } -// decrypto msg from reader, then write into writer -func PipeDecryptoReader(r net.Conn, w net.Conn, key string) { - defer r.Close() - defer w.Close() +func JoinMore(local *Conn, remote *Conn, cryptoKey string) { + var wait sync.WaitGroup + encrypPipe := func(from *Conn, to *Conn, key string) { + defer from.Close() + defer to.Close() + defer wait.Done() + err := PipeEncryptoWriter(from.TcpConn, to.TcpConn, key) + if err != nil { + log.Warn("join conns error, %v", err) + } + } + + decryptoPipe := func(to *Conn, from *Conn, key string) { + defer from.Close() + defer to.Close() + defer wait.Done() + + err := PipeDecryptoReader(to.TcpConn, from.TcpConn, key) + if err != nil { + log.Warn("join conns error, %v", err) + } + } + + wait.Add(2) + go encrypPipe(local, remote, cryptoKey) + go decryptoPipe(remote, local, cryptoKey) + wait.Wait() + return +} + +// decrypto msg from reader, then write into writer +func PipeDecryptoReader(r net.Conn, w net.Conn, key string) error { laes := new(pcrypto.Pcrypto) if err := laes.Init([]byte(key)); err != nil { - log.Error("Pcrypto Init error, [%v]", err) - return + log.Error("Pcrypto Init error: %v", err) + return fmt.Errorf("Pcrypto Init error: %v", err) } nreader := bufio.NewReader(r) - for { buf, err := nreader.ReadBytes('\n') if err != nil { - log.Error("Conn ReadBytes error, [%v]", err) - return + return err } res, err := laes.Decrypto(buf) if err != nil { - log.Error("Decrypto error, [%s] [%s]", err, string(buf)) - return + log.Error("Decrypto [%s] error, %v", string(buf), err) + return fmt.Errorf("Decrypto [%s] error: %v", string(buf), err) } _, err = w.Write(res) if err != nil { - log.Error("net.Conn Write error, [%v]", err) - return + return err } } + return nil } // recvive msg from reader, then encrypto msg into write -func PipeEncryptoWriter(r net.Conn, w net.Conn, key string) { - defer r.Close() - defer w.Close() - +func PipeEncryptoWriter(r net.Conn, w net.Conn, key string) error { laes := new(pcrypto.Pcrypto) if err := laes.Init([]byte(key)); err != nil { - log.Error("Pcrypto Init error, [%v]", err) - return + log.Error("Pcrypto Init error: %v", err) + return fmt.Errorf("Pcrypto Init error: %v", err) } nreader := bufio.NewReader(r) @@ -215,20 +238,19 @@ func PipeEncryptoWriter(r net.Conn, w net.Conn, key string) { for { n, err := nreader.Read(buf) if err != nil { - log.Error("Conn ReadLine error, [%v]", err) - return + return err } res, err := laes.Encrypto(buf[:n]) if err != nil { - log.Error("Encrypto error, [%v]", err) - return + log.Error("Encrypto error: %v", err) + return fmt.Errorf("Encrypto error: %v", err) } res = append(res, '\n') _, err = w.Write(res) if err != nil { - log.Error("net.Conn Write error, [%v]", err) - return + return err } } + return nil } From 52f99bbc00e525af33771114662f726b933b777d Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 31 Mar 2016 18:03:44 +0800 Subject: [PATCH 07/14] all: some optimization --- .travis.yml | 2 +- src/frp/cmd/frpc/control.go | 148 +++++++++--------- src/frp/cmd/frps/control.go | 253 +++++++++++++++++-------------- src/frp/models/client/client.go | 6 +- src/frp/models/consts/consts.go | 20 +-- src/frp/models/msg/msg.go | 17 +-- src/frp/models/server/server.go | 20 +-- src/frp/utils/conn/conn.go | 15 +- src/frp/utils/version/version.go | 2 +- 9 files changed, 253 insertions(+), 230 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8fdbf99d..b5b6a21b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: go go: - 1.4.2 - - 1.5.1 + - 1.5.3 install: - make diff --git a/src/frp/cmd/frpc/control.go b/src/frp/cmd/frpc/control.go index 137be068..3f3ae7f2 100644 --- a/src/frp/cmd/frpc/control.go +++ b/src/frp/cmd/frpc/control.go @@ -28,64 +28,98 @@ import ( "frp/utils/log" ) -var connection *conn.Conn = nil -var heartBeatTimer *time.Timer = nil - func ControlProcess(cli *client.ProxyClient, wait *sync.WaitGroup) { defer wait.Done() + msgSendChan := make(chan interface{}, 1024) + c, err := loginToServer(cli) if err != nil { log.Error("ProxyName [%s], connect to server failed!", cli.Name) return } - connection = c - defer connection.Close() + defer c.Close() + + go heartbeatSender(c, msgSendChan) + + go msgSender(cli, c, msgSendChan) + msgReader(cli, c, msgSendChan) + + close(msgSendChan) +} + +// loop for reading messages from frpc after control connection is established +func msgReader(cli *client.ProxyClient, c *conn.Conn, msgSendChan chan interface{}) error { + // for heartbeat + var heartbeatTimeout bool = false + timer := time.AfterFunc(time.Duration(client.HeartBeatTimeout)*time.Second, func() { + heartbeatTimeout = true + c.Close() + log.Error("ProxyName [%s], heartbeatRes from frps timeout", cli.Name) + }) + defer timer.Stop() for { - // ignore response content now - content, err := connection.ReadLine() - if err == io.EOF || nil == connection || connection.IsClosed() { - log.Debug("ProxyName [%s], server close this control conn", cli.Name) - var sleepTime time.Duration = 1 + buf, err := c.ReadLine() + if err == io.EOF || c == nil || c.IsClosed() { + c.Close() + log.Warn("ProxyName [%s], frps close this control conn!", cli.Name) + var delayTime time.Duration = 1 - // loop until connect to server + // loop until reconnect to frps for { - log.Debug("ProxyName [%s], try to reconnect to server[%s:%d]...", cli.Name, client.ServerAddr, client.ServerPort) - tmpConn, err := loginToServer(cli) + log.Info("ProxyName [%s], try to reconnect to frps [%s:%d]...", cli.Name, client.ServerAddr, client.ServerPort) + c, err = loginToServer(cli) if err == nil { - connection.Close() - connection = tmpConn + go heartbeatSender(c, msgSendChan) break } - if sleepTime < 60 { - sleepTime = sleepTime * 2 + if delayTime < 60 { + delayTime = delayTime * 2 } - time.Sleep(sleepTime * time.Second) + time.Sleep(delayTime * time.Second) } - continue } else if err != nil { - log.Warn("ProxyName [%s], read from server error, %v", cli.Name, err) + log.Warn("ProxyName [%s], read from frps error: %v", cli.Name, err) continue } - clientCtlRes := &msg.ClientCtlRes{} - if err := json.Unmarshal([]byte(content), clientCtlRes); err != nil { - log.Warn("Parse err: %v : %s", err, content) - continue - } - if consts.SCHeartBeatRes == clientCtlRes.GeneralRes.Code { - if heartBeatTimer != nil { - log.Debug("Client rcv heartbeat response") - heartBeatTimer.Reset(time.Duration(client.HeartBeatTimeout) * time.Second) - } else { - log.Error("heartBeatTimer is nil") - } + ctlRes := &msg.ControlRes{} + if err := json.Unmarshal([]byte(buf), &ctlRes); err != nil { + log.Warn("ProxyName [%s], parse msg from frps error: %v : %s", cli.Name, err, buf) continue } - cli.StartTunnel(client.ServerAddr, client.ServerPort) + switch ctlRes.Type { + case consts.HeartbeatRes: + log.Debug("ProxyName [%s], receive heartbeat response", cli.Name) + timer.Reset(time.Duration(client.HeartBeatTimeout) * time.Second) + case consts.NoticeUserConn: + log.Debug("ProxyName [%s], new user connection", cli.Name) + cli.StartTunnel(client.ServerAddr, client.ServerPort) + default: + log.Warn("ProxyName [%s}, unsupport msgType [%d]", cli.Name, ctlRes.Type) + } + } + return nil +} + +// loop for sending messages from channel to frps +func msgSender(cli *client.ProxyClient, c *conn.Conn, msgSendChan chan interface{}) { + for { + msg, ok := <-msgSendChan + if !ok { + break + } + + buf, _ := json.Marshal(msg) + err := c.Write(string(buf) + "\n") + if err != nil { + log.Warn("ProxyName [%s], write to client error, proxy exit", cli.Name) + c.Close() + break + } } } @@ -96,8 +130,8 @@ func loginToServer(cli *client.ProxyClient) (c *conn.Conn, err error) { return } - req := &msg.ClientCtlReq{ - Type: consts.CtlConn, + req := &msg.ControlReq{ + Type: consts.NewCtlConn, ProxyName: cli.Name, Passwd: cli.Passwd, } @@ -115,53 +149,31 @@ func loginToServer(cli *client.ProxyClient) (c *conn.Conn, err error) { } log.Debug("ProxyName [%s], read [%s]", cli.Name, res) - clientCtlRes := &msg.ClientCtlRes{} - if err = json.Unmarshal([]byte(res), &clientCtlRes); err != nil { + ctlRes := &msg.ControlRes{} + if err = json.Unmarshal([]byte(res), &ctlRes); err != nil { log.Error("ProxyName [%s], format server response error, %v", cli.Name, err) return } - if clientCtlRes.Code != 0 { - log.Error("ProxyName [%s], start proxy error, %s", cli.Name, clientCtlRes.Msg) - return c, fmt.Errorf("%s", clientCtlRes.Msg) + if ctlRes.Code != 0 { + log.Error("ProxyName [%s], start proxy error, %s", cli.Name, ctlRes.Msg) + return c, fmt.Errorf("%s", ctlRes.Msg) } - go startHeartBeat(c) - log.Debug("ProxyName [%s], connect to server[%s:%d] success!", cli.Name, client.ServerAddr, client.ServerPort) - + log.Debug("ProxyName [%s], connect to server [%s:%d] success!", cli.Name, client.ServerAddr, client.ServerPort) return } -func startHeartBeat(c *conn.Conn) { - f := func() { - log.Error("HeartBeat timeout!") - if c != nil { - c.Close() - } +func heartbeatSender(c *conn.Conn, msgSendChan chan interface{}) { + heartbeatReq := &msg.ControlReq{ + Type: consts.HeartbeatReq, } - heartBeatTimer = time.AfterFunc(time.Duration(client.HeartBeatTimeout)*time.Second, f) - defer heartBeatTimer.Stop() - - clientCtlReq := &msg.ClientCtlReq{ - Type: consts.CSHeartBeatReq, - ProxyName: "", - Passwd: "", - } - request, err := json.Marshal(clientCtlReq) - if err != nil { - log.Warn("Serialize clientCtlReq err! Err: %v", err) - } - - log.Debug("Start to send heartbeat") + log.Info("Start to send heartbeat to frps") for { time.Sleep(time.Duration(client.HeartBeatInterval) * time.Second) if c != nil && !c.IsClosed() { log.Debug("Send heartbeat to server") - err = c.Write(string(request) + "\n") - if err != nil { - log.Error("Send hearbeat to server failed! Err:%v", err) - continue - } + msgSendChan <- heartbeatReq } else { break } diff --git a/src/frp/cmd/frps/control.go b/src/frp/cmd/frps/control.go index b60365b6..4402db50 100644 --- a/src/frp/cmd/frps/control.go +++ b/src/frp/cmd/frps/control.go @@ -33,87 +33,162 @@ func ProcessControlConn(l *conn.Listener) { if err != nil { return } - log.Debug("Get one new conn, %v", c.GetRemoteAddr()) + log.Debug("Get new connection, %v", c.GetRemoteAddr()) go controlWorker(c) } } // connection from every client and server func controlWorker(c *conn.Conn) { - // the first message is from client to server - // if error, close connection - res, err := c.ReadLine() + // if login message type is NewWorkConn, don't close this connection + var closeFlag bool = true + var s *server.ProxyServer + defer func() { + if closeFlag { + c.Close() + if s != nil { + s.Close() + } + } + }() + + // get login message + buf, err := c.ReadLine() if err != nil { log.Warn("Read error, %v", err) return } - log.Debug("get: %s", res) + log.Debug("Get msg from frpc: %s", buf) - clientCtlReq := &msg.ClientCtlReq{} - clientCtlRes := &msg.ClientCtlRes{} - if err := json.Unmarshal([]byte(res), &clientCtlReq); err != nil { - log.Warn("Parse err: %v : %s", err, res) + cliReq := &msg.ControlReq{} + if err := json.Unmarshal([]byte(buf), &cliReq); err != nil { + log.Warn("Parse msg from frpc error: %v : %s", err, buf) return } - // check - succ, info, needRes := checkProxy(clientCtlReq, c) - if !succ { - clientCtlRes.Code = 1 - clientCtlRes.Msg = info + // do login when type is NewCtlConn or NewWorkConn + ret, info := doLogin(cliReq, c) + s, ok := server.ProxyServers[cliReq.ProxyName] + if !ok { + log.Warn("ProxyName [%s] is not exist", cliReq.ProxyName) + return } - - if needRes { - defer c.Close() - - buf, _ := json.Marshal(clientCtlRes) - err = c.Write(string(buf) + "\n") + // if login type is NewWorkConn, nothing will be send to frpc + if cliReq.Type != consts.NewWorkConn { + cliRes := &msg.ControlRes{ + Type: consts.NewCtlConnRes, + Code: ret, + Msg: info, + } + byteBuf, _ := json.Marshal(cliRes) + err = c.Write(string(byteBuf) + "\n") if err != nil { - log.Warn("Write error, %v", err) + log.Warn("ProxyName [%s], write to client error, proxy exit", s.Name) time.Sleep(1 * time.Second) return } } else { - // work conn, just return + closeFlag = false return } - // other messages is from server to client - s, ok := server.ProxyServers[clientCtlReq.ProxyName] - if !ok { - log.Warn("ProxyName [%s] is not exist", clientCtlReq.ProxyName) - return - } + // create a channel for sending messages + msgSendChan := make(chan interface{}, 1024) + go msgSender(s, c, msgSendChan) + go noticeUserConn(s, msgSendChan) - // read control msg from client - go readControlMsgFromClient(s, c) - - serverCtlReq := &msg.ClientCtlReq{} - serverCtlReq.Type = consts.WorkConn - for { - closeFlag := s.WaitUserConn() - if closeFlag { - log.Debug("ProxyName [%s], goroutine for dealing user conn is closed", s.Name) - break - } - buf, _ := json.Marshal(serverCtlReq) - err = c.Write(string(buf) + "\n") - if err != nil { - log.Warn("ProxyName [%s], write to client error, proxy exit", s.Name) - s.Close() - return - } - - log.Debug("ProxyName [%s], write to client to add work conn success", s.Name) - } + // loop for reading control messages from frpc and deal with different types + msgReader(s, c, msgSendChan) + close(msgSendChan) log.Info("ProxyName [%s], I'm dead!", s.Name) return } -func checkProxy(req *msg.ClientCtlReq, c *conn.Conn) (succ bool, info string, needRes bool) { - succ = false - needRes = true +// when frps get one new user connection, send NoticeUserConn message to frpc and accept one new WorkConn later +func noticeUserConn(s *server.ProxyServer, msgSendChan chan interface{}) { + for { + closeFlag := s.WaitUserConn() + if closeFlag { + log.Debug("ProxyName [%s], goroutine for noticing user conn is closed", s.Name) + break + } + notice := &msg.ControlRes{ + Type: consts.NoticeUserConn, + } + msgSendChan <- notice + log.Debug("ProxyName [%s], notice client to add work conn", s.Name) + } +} + +// loop for reading messages from frpc after control connection is established +func msgReader(s *server.ProxyServer, c *conn.Conn, msgSendChan chan interface{}) error { + // for heartbeat + var heartbeatTimeout bool = false + timer := time.AfterFunc(time.Duration(server.HeartBeatTimeout)*time.Second, func() { + heartbeatTimeout = true + s.Close() + c.Close() + log.Error("ProxyName [%s], client heartbeat timeout", s.Name) + }) + defer timer.Stop() + + for { + buf, err := c.ReadLine() + if err != nil { + if err == io.EOF { + log.Warn("ProxyName [%s], client is dead!", s.Name) + return err + } else if c == nil || c.IsClosed() { + log.Warn("ProxyName [%s], client connection is closed", s.Name) + return err + } + log.Warn("ProxyName [%s], read error: %v", s.Name, err) + continue + } + + cliReq := &msg.ControlReq{} + if err := json.Unmarshal([]byte(buf), &cliReq); err != nil { + log.Warn("ProxyName [%s], parse msg from frpc error: %v : %s", s.Name, err, buf) + continue + } + + switch cliReq.Type { + case consts.HeartbeatReq: + log.Debug("ProxyName [%s], get heartbeat", s.Name) + timer.Reset(time.Duration(server.HeartBeatTimeout) * time.Second) + heartbeatRes := msg.ControlRes{ + Type: consts.HeartbeatRes, + } + msgSendChan <- heartbeatRes + default: + log.Warn("ProxyName [%s}, unsupport msgType [%d]", s.Name, cliReq.Type) + } + } + return nil +} + +// loop for sending messages from channel to frpc +func msgSender(s *server.ProxyServer, c *conn.Conn, msgSendChan chan interface{}) { + for { + msg, ok := <-msgSendChan + if !ok { + break + } + + buf, _ := json.Marshal(msg) + err := c.Write(string(buf) + "\n") + if err != nil { + log.Warn("ProxyName [%s], write to client error, proxy exit", s.Name) + s.Close() + break + } + } +} + +// if success, ret equals 0, otherwise greater than 0 +func doLogin(req *msg.ControlReq, c *conn.Conn) (ret int64, info string) { + ret = 1 // check if proxy name exist s, ok := server.ProxyServers[req.ProxyName] if !ok { @@ -130,89 +205,35 @@ func checkProxy(req *msg.ClientCtlReq, c *conn.Conn) (succ bool, info string, ne } // control conn - if req.Type == consts.CtlConn { + if req.Type == consts.NewCtlConn { if s.Status != consts.Idle { info = fmt.Sprintf("ProxyName [%s], already in use", req.ProxyName) log.Warn(info) return } - // start proxy and listen for user conn, no block + // start proxy and listen for user connections, no block err := s.Start() if err != nil { - info = fmt.Sprintf("ProxyName [%s], start proxy error: %v", req.ProxyName, err.Error()) + info = fmt.Sprintf("ProxyName [%s], start proxy error: %v", req.ProxyName, err) log.Warn(info) return } - log.Info("ProxyName [%s], start proxy success", req.ProxyName) - } else if req.Type == consts.WorkConn { + } else if req.Type == consts.NewWorkConn { // work conn - needRes = false if s.Status != consts.Working { - log.Warn("ProxyName [%s], is not working when it gets one new work conn", req.ProxyName) + log.Warn("ProxyName [%s], is not working when it gets one new work connnection", req.ProxyName) return } - - s.GetNewCliConn(c) + // the connection will close after join over + s.RecvNewWorkConn(c) } else { - info = fmt.Sprintf("ProxyName [%s], type [%d] unsupport", req.ProxyName, req.Type) - log.Warn(info) + info = fmt.Sprintf("Unsupport login message type [%d]", req.Type) + log.Warn("Unsupport login message type [%d]", req.Type) return } - succ = true + ret = 0 return } - -func readControlMsgFromClient(s *server.ProxyServer, c *conn.Conn) { - isContinueRead := true - f := func() { - isContinueRead = false - s.Close() - log.Error("ProxyName [%s], client heartbeat timeout", s.Name) - } - timer := time.AfterFunc(time.Duration(server.HeartBeatTimeout)*time.Second, f) - defer timer.Stop() - - for isContinueRead { - content, err := c.ReadLine() - if err != nil { - if err == io.EOF { - log.Warn("ProxyName [%s], client is dead!", s.Name) - s.Close() - break - } else if nil == c || c.IsClosed() { - log.Warn("ProxyName [%s], client connection is closed", s.Name) - break - } - - log.Error("ProxyName [%s], read error: %v", s.Name, err) - continue - } - - clientCtlReq := &msg.ClientCtlReq{} - if err := json.Unmarshal([]byte(content), clientCtlReq); err != nil { - log.Warn("Parse err: %v : %s", err, content) - continue - } - if consts.CSHeartBeatReq == clientCtlReq.Type { - log.Debug("ProxyName [%s], get heartbeat", s.Name) - timer.Reset(time.Duration(server.HeartBeatTimeout) * time.Second) - - clientCtlRes := &msg.ClientCtlRes{} - clientCtlRes.GeneralRes.Code = consts.SCHeartBeatRes - response, err := json.Marshal(clientCtlRes) - if err != nil { - log.Warn("Serialize ClientCtlRes err! err: %v", err) - continue - } - - err = c.Write(string(response) + "\n") - if err != nil { - log.Error("Send heartbeat response to client failed! Err:%v", err) - continue - } - } - } -} diff --git a/src/frp/models/client/client.go b/src/frp/models/client/client.go index 6b85a17b..00164279 100644 --- a/src/frp/models/client/client.go +++ b/src/frp/models/client/client.go @@ -51,8 +51,8 @@ func (p *ProxyClient) GetRemoteConn(addr string, port int64) (c *conn.Conn, err return } - req := &msg.ClientCtlReq{ - Type: consts.WorkConn, + req := &msg.ControlReq{ + Type: consts.NewWorkConn, ProxyName: p.Name, Passwd: p.Passwd, } @@ -79,7 +79,7 @@ func (p *ProxyClient) StartTunnel(serverAddr string, serverPort int64) (err erro } // l means local, r means remote - log.Debug("Join two conns, (l[%s] r[%s]) (l[%s] r[%s])", localConn.GetLocalAddr(), localConn.GetRemoteAddr(), + log.Debug("Join two connections, (l[%s] r[%s]) (l[%s] r[%s])", localConn.GetLocalAddr(), localConn.GetRemoteAddr(), remoteConn.GetLocalAddr(), remoteConn.GetRemoteAddr()) // go conn.Join(localConn, remoteConn) go conn.JoinMore(localConn, remoteConn, p.Passwd) diff --git a/src/frp/models/consts/consts.go b/src/frp/models/consts/consts.go index 56191ff6..342046e1 100644 --- a/src/frp/models/consts/consts.go +++ b/src/frp/models/consts/consts.go @@ -20,18 +20,12 @@ const ( Working ) -// connection type +// msg type const ( - CtlConn = iota - WorkConn -) - -// msg from client to server -const ( - CSHeartBeatReq = 1 -) - -// msg from server to client -const ( - SCHeartBeatRes = 100 + NewCtlConn = iota + NewWorkConn + NoticeUserConn + NewCtlConnRes + HeartbeatReq + HeartbeatRes ) diff --git a/src/frp/models/msg/msg.go b/src/frp/models/msg/msg.go index 5c62bfb6..83b77f6b 100644 --- a/src/frp/models/msg/msg.go +++ b/src/frp/models/msg/msg.go @@ -19,16 +19,15 @@ type GeneralRes struct { Msg string `json:"msg"` } -type ClientCtlReq struct { +// messages between control connection of frpc and frps +type ControlReq struct { Type int64 `json:"type"` - ProxyName string `json:"proxy_name"` - Passwd string `json:"passwd"` + ProxyName string `json:"proxy_name,omitempty"` + Passwd string `json:"passwd, omitempty"` } -type ClientCtlRes struct { - GeneralRes -} - -type ServerCtlReq struct { - Type int64 `json:"type"` +type ControlRes struct { + Type int64 `json:"type"` + Code int64 `json:"code"` + Msg string `json:"msg"` } diff --git a/src/frp/models/server/server.go b/src/frp/models/server/server.go index f59bcdcb..bb6373c3 100644 --- a/src/frp/models/server/server.go +++ b/src/frp/models/server/server.go @@ -33,14 +33,14 @@ type ProxyServer struct { listener *conn.Listener // accept new connection from remote users ctlMsgChan chan int64 // every time accept a new user conn, put "1" to the channel - cliConnChan chan *conn.Conn // get client conns from control goroutine + workConnChan chan *conn.Conn // get new work conns from control goroutine userConnList *list.List // store user conns mutex sync.Mutex } func (p *ProxyServer) Init() { p.Status = consts.Idle - p.cliConnChan = make(chan *conn.Conn) + p.workConnChan = make(chan *conn.Conn) p.ctlMsgChan = make(chan int64) p.userConnList = list.New() } @@ -109,7 +109,7 @@ func (p *ProxyServer) Start() (err error) { // start another goroutine for join two conns from client and user go func() { for { - cliConn, ok := <-p.cliConnChan + workConn, ok := <-p.workConnChan if !ok { return } @@ -122,7 +122,7 @@ func (p *ProxyServer) Start() (err error) { userConn = element.Value.(*conn.Conn) p.userConnList.Remove(element) } else { - cliConn.Close() + workConn.Close() p.Unlock() continue } @@ -130,10 +130,10 @@ func (p *ProxyServer) Start() (err error) { // msg will transfer to another without modifying // l means local, r means remote - log.Debug("Join two conns, (l[%s] r[%s]) (l[%s] r[%s])", cliConn.GetLocalAddr(), cliConn.GetRemoteAddr(), + log.Debug("Join two connections, (l[%s] r[%s]) (l[%s] r[%s])", workConn.GetLocalAddr(), workConn.GetRemoteAddr(), userConn.GetLocalAddr(), userConn.GetRemoteAddr()) - // go conn.Join(cliConn, userConn) - go conn.JoinMore(userConn, cliConn, p.Passwd) + // go conn.Join(workConn, userConn) + go conn.JoinMore(userConn, workConn, p.Passwd) } }() @@ -147,7 +147,7 @@ func (p *ProxyServer) Close() { p.listener.Close() } close(p.ctlMsgChan) - close(p.cliConnChan) + close(p.workConnChan) p.userConnList = list.New() p.Unlock() } @@ -162,6 +162,6 @@ func (p *ProxyServer) WaitUserConn() (closeFlag bool) { return } -func (p *ProxyServer) GetNewCliConn(c *conn.Conn) { - p.cliConnChan <- c +func (p *ProxyServer) RecvNewWorkConn(c *conn.Conn) { + p.workConnChan <- c } diff --git a/src/frp/utils/conn/conn.go b/src/frp/utils/conn/conn.go index b3738bdc..0f199cfc 100644 --- a/src/frp/utils/conn/conn.go +++ b/src/frp/utils/conn/conn.go @@ -153,7 +153,7 @@ func Join(c1 *Conn, c2 *Conn) { var err error _, err = io.Copy(to.TcpConn, from.TcpConn) if err != nil { - log.Warn("join conns error, %v", err) + log.Warn("join connections error, %v", err) } } @@ -171,10 +171,8 @@ func JoinMore(local *Conn, remote *Conn, cryptoKey string) { defer to.Close() defer wait.Done() - err := PipeEncryptoWriter(from.TcpConn, to.TcpConn, key) - if err != nil { - log.Warn("join conns error, %v", err) - } + // we don't care about errors here + PipeEncryptoWriter(from.TcpConn, to.TcpConn, key) } decryptoPipe := func(to *Conn, from *Conn, key string) { @@ -182,16 +180,15 @@ func JoinMore(local *Conn, remote *Conn, cryptoKey string) { defer to.Close() defer wait.Done() - err := PipeDecryptoReader(to.TcpConn, from.TcpConn, key) - if err != nil { - log.Warn("join conns error, %v", err) - } + // we don't care about errors here + PipeDecryptoReader(to.TcpConn, from.TcpConn, key) } wait.Add(2) go encrypPipe(local, remote, cryptoKey) go decryptoPipe(remote, local, cryptoKey) wait.Wait() + log.Debug("One tunnel stopped") return } diff --git a/src/frp/utils/version/version.go b/src/frp/utils/version/version.go index 680fa8c1..075a4c8d 100644 --- a/src/frp/utils/version/version.go +++ b/src/frp/utils/version/version.go @@ -19,7 +19,7 @@ import ( "strings" ) -var version string = "0.2.0" +var version string = "0.3.0" func Full() string { return version From 80fc76da52a422b3620f5cceec29bfd6b88bb226 Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 31 Mar 2016 18:48:18 +0800 Subject: [PATCH 08/14] all: now messages between frps and frpc can be encryped when use_encryption set true --- README.md | 2 +- conf/frpc.ini | 2 ++ src/frp/cmd/frpc/control.go | 7 +++--- src/frp/cmd/frps/control.go | 3 +++ src/frp/models/client/client.go | 16 +++++++----- src/frp/models/client/config.go | 11 ++++++++ src/frp/models/msg/msg.go | 7 +++--- src/frp/models/server/server.go | 19 ++++++++------ src/frp/utils/conn/conn.go | 36 ++++++++++++++------------- src/frp/utils/pcrypto/pcrypto.go | 4 +-- src/frp/utils/pcrypto/pcrypto_test.go | 10 ++++---- 11 files changed, 73 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 1c204d13..14e81ec0 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ frp is a fast reverse proxy to help you expose a local server behind a NAT or fi ## Status -frp is under development and you can try it with available version 0.2.0. +frp is under development and you can try it with available version 0.3.0. ## Quick Start diff --git a/conf/frpc.ini b/conf/frpc.ini index 09dfeb75..50a37604 100644 --- a/conf/frpc.ini +++ b/conf/frpc.ini @@ -12,3 +12,5 @@ log_level = debug passwd = 123 local_ip = 127.0.0.1 local_port = 22 +# true or false, if true, messages between frps and frpc will be encrypted, default is false +use_encryption = true diff --git a/src/frp/cmd/frpc/control.go b/src/frp/cmd/frpc/control.go index 3f3ae7f2..3ca8bada 100644 --- a/src/frp/cmd/frpc/control.go +++ b/src/frp/cmd/frpc/control.go @@ -131,9 +131,10 @@ func loginToServer(cli *client.ProxyClient) (c *conn.Conn, err error) { } req := &msg.ControlReq{ - Type: consts.NewCtlConn, - ProxyName: cli.Name, - Passwd: cli.Passwd, + Type: consts.NewCtlConn, + ProxyName: cli.Name, + Passwd: cli.Passwd, + UseEncryption: cli.UseEncryption, } buf, _ := json.Marshal(req) err = c.Write(string(buf) + "\n") diff --git a/src/frp/cmd/frps/control.go b/src/frp/cmd/frps/control.go index 4402db50..dc2eb53c 100644 --- a/src/frp/cmd/frps/control.go +++ b/src/frp/cmd/frps/control.go @@ -212,6 +212,9 @@ func doLogin(req *msg.ControlReq, c *conn.Conn) (ret int64, info string) { return } + // set infomations from frpc + s.UseEncryption = req.UseEncryption + // start proxy and listen for user connections, no block err := s.Start() if err != nil { diff --git a/src/frp/models/client/client.go b/src/frp/models/client/client.go index 00164279..8310610e 100644 --- a/src/frp/models/client/client.go +++ b/src/frp/models/client/client.go @@ -24,10 +24,11 @@ import ( ) type ProxyClient struct { - Name string - Passwd string - LocalIp string - LocalPort int64 + Name string + Passwd string + LocalIp string + LocalPort int64 + UseEncryption bool } func (p *ProxyClient) GetLocalConn() (c *conn.Conn, err error) { @@ -81,8 +82,11 @@ func (p *ProxyClient) StartTunnel(serverAddr string, serverPort int64) (err erro // l means local, r means remote log.Debug("Join two connections, (l[%s] r[%s]) (l[%s] r[%s])", localConn.GetLocalAddr(), localConn.GetRemoteAddr(), remoteConn.GetLocalAddr(), remoteConn.GetRemoteAddr()) - // go conn.Join(localConn, remoteConn) - go conn.JoinMore(localConn, remoteConn, p.Passwd) + if p.UseEncryption { + go conn.JoinMore(localConn, remoteConn, p.Passwd) + } else { + go conn.Join(localConn, remoteConn) + } return nil } diff --git a/src/frp/models/client/config.go b/src/frp/models/client/config.go index e41fec82..1e947430 100644 --- a/src/frp/models/client/config.go +++ b/src/frp/models/client/config.go @@ -73,19 +73,23 @@ func LoadConf(confFile string) (err error) { for name, section := range conf { if name != "common" { proxyClient := &ProxyClient{} + // name proxyClient.Name = name + // passwd proxyClient.Passwd, ok = section["passwd"] if !ok { return fmt.Errorf("Parse ini file error: proxy [%s] no passwd found", proxyClient.Name) } + // local_ip proxyClient.LocalIp, ok = section["local_ip"] if !ok { // use 127.0.0.1 as default proxyClient.LocalIp = "127.0.0.1" } + // local_port portStr, ok := section["local_port"] if ok { proxyClient.LocalPort, err = strconv.ParseInt(portStr, 10, 64) @@ -96,6 +100,13 @@ func LoadConf(confFile string) (err error) { return fmt.Errorf("Parse ini file error: proxy [%s] local_port not found", proxyClient.Name) } + // use_encryption + proxyClient.UseEncryption = false + useEncryptionStr, ok := section["use_encryption"] + if ok && useEncryptionStr == "true" { + proxyClient.UseEncryption = true + } + ProxyClients[proxyClient.Name] = proxyClient } } diff --git a/src/frp/models/msg/msg.go b/src/frp/models/msg/msg.go index 83b77f6b..5bc21ed2 100644 --- a/src/frp/models/msg/msg.go +++ b/src/frp/models/msg/msg.go @@ -21,9 +21,10 @@ type GeneralRes struct { // messages between control connection of frpc and frps type ControlReq struct { - Type int64 `json:"type"` - ProxyName string `json:"proxy_name,omitempty"` - Passwd string `json:"passwd, omitempty"` + Type int64 `json:"type"` + ProxyName string `json:"proxy_name,omitempty"` + Passwd string `json:"passwd, omitempty"` + UseEncryption bool `json:"use_encryption, omitempty"` } type ControlRes struct { diff --git a/src/frp/models/server/server.go b/src/frp/models/server/server.go index bb6373c3..8f285d05 100644 --- a/src/frp/models/server/server.go +++ b/src/frp/models/server/server.go @@ -25,11 +25,12 @@ import ( ) type ProxyServer struct { - Name string - Passwd string - BindAddr string - ListenPort int64 - Status int64 + Name string + Passwd string + UseEncryption bool + BindAddr string + ListenPort int64 + Status int64 listener *conn.Listener // accept new connection from remote users ctlMsgChan chan int64 // every time accept a new user conn, put "1" to the channel @@ -132,8 +133,12 @@ func (p *ProxyServer) Start() (err error) { // l means local, r means remote log.Debug("Join two connections, (l[%s] r[%s]) (l[%s] r[%s])", workConn.GetLocalAddr(), workConn.GetRemoteAddr(), userConn.GetLocalAddr(), userConn.GetRemoteAddr()) - // go conn.Join(workConn, userConn) - go conn.JoinMore(userConn, workConn, p.Passwd) + + if p.UseEncryption { + go conn.JoinMore(userConn, workConn, p.Passwd) + } else { + go conn.Join(userConn, workConn) + } } }() diff --git a/src/frp/utils/conn/conn.go b/src/frp/utils/conn/conn.go index 0f199cfc..eb064c4a 100644 --- a/src/frp/utils/conn/conn.go +++ b/src/frp/utils/conn/conn.go @@ -164,36 +164,38 @@ func Join(c1 *Conn, c2 *Conn) { return } -func JoinMore(local *Conn, remote *Conn, cryptoKey string) { +// messages from c1 to c2 will be encrypted +// and from c2 to c1 will be decrypted +func JoinMore(c1 *Conn, c2 *Conn, cryptKey string) { var wait sync.WaitGroup - encrypPipe := func(from *Conn, to *Conn, key string) { + encryptPipe := func(from *Conn, to *Conn, key string) { defer from.Close() defer to.Close() defer wait.Done() // we don't care about errors here - PipeEncryptoWriter(from.TcpConn, to.TcpConn, key) + PipeEncrypt(from.TcpConn, to.TcpConn, key) } - decryptoPipe := func(to *Conn, from *Conn, key string) { + decryptPipe := func(to *Conn, from *Conn, key string) { defer from.Close() defer to.Close() defer wait.Done() // we don't care about errors here - PipeDecryptoReader(to.TcpConn, from.TcpConn, key) + PipeDecrypt(to.TcpConn, from.TcpConn, key) } wait.Add(2) - go encrypPipe(local, remote, cryptoKey) - go decryptoPipe(remote, local, cryptoKey) + go encryptPipe(c1, c2, cryptKey) + go decryptPipe(c2, c1, cryptKey) wait.Wait() log.Debug("One tunnel stopped") return } -// decrypto msg from reader, then write into writer -func PipeDecryptoReader(r net.Conn, w net.Conn, key string) error { +// decrypt msg from reader, then write into writer +func PipeDecrypt(r net.Conn, w net.Conn, key string) error { laes := new(pcrypto.Pcrypto) if err := laes.Init([]byte(key)); err != nil { log.Error("Pcrypto Init error: %v", err) @@ -207,10 +209,10 @@ func PipeDecryptoReader(r net.Conn, w net.Conn, key string) error { return err } - res, err := laes.Decrypto(buf) + res, err := laes.Decrypt(buf) if err != nil { - log.Error("Decrypto [%s] error, %v", string(buf), err) - return fmt.Errorf("Decrypto [%s] error: %v", string(buf), err) + log.Error("Decrypt [%s] error, %v", string(buf), err) + return fmt.Errorf("Decrypt [%s] error: %v", string(buf), err) } _, err = w.Write(res) @@ -221,8 +223,8 @@ func PipeDecryptoReader(r net.Conn, w net.Conn, key string) error { return nil } -// recvive msg from reader, then encrypto msg into write -func PipeEncryptoWriter(r net.Conn, w net.Conn, key string) error { +// recvive msg from reader, then encrypt msg into write +func PipeEncrypt(r net.Conn, w net.Conn, key string) error { laes := new(pcrypto.Pcrypto) if err := laes.Init([]byte(key)); err != nil { log.Error("Pcrypto Init error: %v", err) @@ -237,10 +239,10 @@ func PipeEncryptoWriter(r net.Conn, w net.Conn, key string) error { if err != nil { return err } - res, err := laes.Encrypto(buf[:n]) + res, err := laes.Encrypt(buf[:n]) if err != nil { - log.Error("Encrypto error: %v", err) - return fmt.Errorf("Encrypto error: %v", err) + log.Error("Encrypt error: %v", err) + return fmt.Errorf("Encrypt error: %v", err) } res = append(res, '\n') diff --git a/src/frp/utils/pcrypto/pcrypto.go b/src/frp/utils/pcrypto/pcrypto.go index 8a4435e2..c2a25178 100644 --- a/src/frp/utils/pcrypto/pcrypto.go +++ b/src/frp/utils/pcrypto/pcrypto.go @@ -39,7 +39,7 @@ func (pc *Pcrypto) Init(key []byte) error { return err } -func (pc *Pcrypto) Encrypto(src []byte) ([]byte, error) { +func (pc *Pcrypto) Encrypt(src []byte) ([]byte, error) { // aes src = pKCS7Padding(src, aes.BlockSize) blockMode := cipher.NewCBCEncrypter(pc.paes, pc.pkey) @@ -57,7 +57,7 @@ func (pc *Pcrypto) Encrypto(src []byte) ([]byte, error) { return []byte(base64.StdEncoding.EncodeToString(zbuf.Bytes())), nil } -func (pc *Pcrypto) Decrypto(str []byte) ([]byte, error) { +func (pc *Pcrypto) Decrypt(str []byte) ([]byte, error) { // base64 data, err := base64.StdEncoding.DecodeString(string(str)) if err != nil { diff --git a/src/frp/utils/pcrypto/pcrypto_test.go b/src/frp/utils/pcrypto/pcrypto_test.go index 016dd529..e86762fe 100644 --- a/src/frp/utils/pcrypto/pcrypto_test.go +++ b/src/frp/utils/pcrypto/pcrypto_test.go @@ -19,10 +19,10 @@ import ( "testing" ) -func TestEncrypto(t *testing.T) { +func TestEncrypt(t *testing.T) { pp := new(Pcrypto) pp.Init([]byte("Hana")) - res, err := pp.Encrypto([]byte("Just One Test!")) + res, err := pp.Encrypt([]byte("Just One Test!")) if err != nil { t.Fatal(err) } @@ -30,15 +30,15 @@ func TestEncrypto(t *testing.T) { fmt.Printf("[%x]\n", res) } -func TestDecrypto(t *testing.T) { +func TestDecrypt(t *testing.T) { pp := new(Pcrypto) pp.Init([]byte("Hana")) - res, err := pp.Encrypto([]byte("Just One Test!")) + res, err := pp.Encrypt([]byte("Just One Test!")) if err != nil { t.Fatal(err) } - res, err = pp.Decrypto(res) + res, err = pp.Decrypt(res) if err != nil { t.Fatal(err) } From b3ee746be8370895a664d03a1ba46c5d9b118995 Mon Sep 17 00:00:00 2001 From: fatedier Date: Tue, 5 Apr 2016 15:25:55 +0800 Subject: [PATCH 09/14] optimize compress --- src/frp/utils/conn/conn.go | 4 +-- src/frp/utils/pcrypto/pcrypto.go | 54 ++++++++++++++------------------ 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/frp/utils/conn/conn.go b/src/frp/utils/conn/conn.go index eb064c4a..a7df1464 100644 --- a/src/frp/utils/conn/conn.go +++ b/src/frp/utils/conn/conn.go @@ -209,7 +209,7 @@ func PipeDecrypt(r net.Conn, w net.Conn, key string) error { return err } - res, err := laes.Decrypt(buf) + res, err := laes.Decrypto(buf) if err != nil { log.Error("Decrypt [%s] error, %v", string(buf), err) return fmt.Errorf("Decrypt [%s] error: %v", string(buf), err) @@ -239,7 +239,7 @@ func PipeEncrypt(r net.Conn, w net.Conn, key string) error { if err != nil { return err } - res, err := laes.Encrypt(buf[:n]) + res, err := laes.Encrypto(buf[:n]) if err != nil { log.Error("Encrypt error: %v", err) return fmt.Errorf("Encrypt error: %v", err) diff --git a/src/frp/utils/pcrypto/pcrypto.go b/src/frp/utils/pcrypto/pcrypto.go index c2a25178..308a41fa 100644 --- a/src/frp/utils/pcrypto/pcrypto.go +++ b/src/frp/utils/pcrypto/pcrypto.go @@ -1,17 +1,3 @@ -// Copyright 2016 fatedier, fatedier@gmail.com -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package pcrypto import ( @@ -39,37 +25,37 @@ func (pc *Pcrypto) Init(key []byte) error { return err } -func (pc *Pcrypto) Encrypt(src []byte) ([]byte, error) { +func (pc *Pcrypto) Encrypto(src []byte) ([]byte, error) { + // gzip + var zbuf bytes.Buffer + zwr, err := gzip.NewWriterLevel(&zbuf, -1) + if err != nil { + return nil, err + } + defer zwr.Close() + zwr.Write(src) + zwr.Flush() + fmt.Println("com,src,en", len(src), len(zbuf.Bytes())) + // aes - src = pKCS7Padding(src, aes.BlockSize) + src = pKCS7Padding(zbuf.Bytes(), aes.BlockSize) blockMode := cipher.NewCBCEncrypter(pc.paes, pc.pkey) crypted := make([]byte, len(src)) blockMode.CryptBlocks(crypted, src) - // gzip - var zbuf bytes.Buffer - zwr := gzip.NewWriter(&zbuf) - defer zwr.Close() - zwr.Write(crypted) - zwr.Flush() + fmt.Println("aes,src,en", len(src), len(crypted)) // base64 - return []byte(base64.StdEncoding.EncodeToString(zbuf.Bytes())), nil + return []byte(base64.StdEncoding.EncodeToString(crypted)), nil } -func (pc *Pcrypto) Decrypt(str []byte) ([]byte, error) { +func (pc *Pcrypto) Decrypto(str []byte) ([]byte, error) { // base64 data, err := base64.StdEncoding.DecodeString(string(str)) if err != nil { return nil, err } - // gunzip - zbuf := bytes.NewBuffer(data) - zrd, _ := gzip.NewReader(zbuf) - defer zrd.Close() - data, _ = ioutil.ReadAll(zrd) - // aes decryptText, err := hex.DecodeString(fmt.Sprintf("%x", data)) if err != nil { @@ -85,7 +71,13 @@ func (pc *Pcrypto) Decrypt(str []byte) ([]byte, error) { blockMode.CryptBlocks(decryptText, decryptText) decryptText = pKCS7UnPadding(decryptText) - return decryptText, nil + // gunzip + zbuf := bytes.NewBuffer(decryptText) + zrd, _ := gzip.NewReader(zbuf) + defer zrd.Close() + data, _ = ioutil.ReadAll(zrd) + + return data, nil } func pKCS7Padding(ciphertext []byte, blockSize int) []byte { From 718e707b77f97af6cc7bf8ad3c5e70630ff17458 Mon Sep 17 00:00:00 2001 From: fatedier Date: Tue, 5 Apr 2016 15:40:32 +0800 Subject: [PATCH 10/14] pcrypto: fix --- src/frp/utils/conn/conn.go | 4 ++-- src/frp/utils/pcrypto/pcrypto.go | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/frp/utils/conn/conn.go b/src/frp/utils/conn/conn.go index a7df1464..eb064c4a 100644 --- a/src/frp/utils/conn/conn.go +++ b/src/frp/utils/conn/conn.go @@ -209,7 +209,7 @@ func PipeDecrypt(r net.Conn, w net.Conn, key string) error { return err } - res, err := laes.Decrypto(buf) + res, err := laes.Decrypt(buf) if err != nil { log.Error("Decrypt [%s] error, %v", string(buf), err) return fmt.Errorf("Decrypt [%s] error: %v", string(buf), err) @@ -239,7 +239,7 @@ func PipeEncrypt(r net.Conn, w net.Conn, key string) error { if err != nil { return err } - res, err := laes.Encrypto(buf[:n]) + res, err := laes.Encrypt(buf[:n]) if err != nil { log.Error("Encrypt error: %v", err) return fmt.Errorf("Encrypt error: %v", err) diff --git a/src/frp/utils/pcrypto/pcrypto.go b/src/frp/utils/pcrypto/pcrypto.go index 308a41fa..ebddfac8 100644 --- a/src/frp/utils/pcrypto/pcrypto.go +++ b/src/frp/utils/pcrypto/pcrypto.go @@ -1,3 +1,17 @@ +// Copyright 2016 fatedier, fatedier@gmail.com +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package pcrypto import ( @@ -25,7 +39,7 @@ func (pc *Pcrypto) Init(key []byte) error { return err } -func (pc *Pcrypto) Encrypto(src []byte) ([]byte, error) { +func (pc *Pcrypto) Encrypt(src []byte) ([]byte, error) { // gzip var zbuf bytes.Buffer zwr, err := gzip.NewWriterLevel(&zbuf, -1) @@ -49,7 +63,7 @@ func (pc *Pcrypto) Encrypto(src []byte) ([]byte, error) { return []byte(base64.StdEncoding.EncodeToString(crypted)), nil } -func (pc *Pcrypto) Decrypto(str []byte) ([]byte, error) { +func (pc *Pcrypto) Decrypt(str []byte) ([]byte, error) { // base64 data, err := base64.StdEncoding.DecodeString(string(str)) if err != nil { From a729a4fafeefa38b1018ac2d1a631ef93b364967 Mon Sep 17 00:00:00 2001 From: fatedier Date: Tue, 5 Apr 2016 16:17:31 +0800 Subject: [PATCH 11/14] pcrypto: update --- src/frp/utils/pcrypto/pcrypto.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/frp/utils/pcrypto/pcrypto.go b/src/frp/utils/pcrypto/pcrypto.go index ebddfac8..2e8ba928 100644 --- a/src/frp/utils/pcrypto/pcrypto.go +++ b/src/frp/utils/pcrypto/pcrypto.go @@ -49,7 +49,6 @@ func (pc *Pcrypto) Encrypt(src []byte) ([]byte, error) { defer zwr.Close() zwr.Write(src) zwr.Flush() - fmt.Println("com,src,en", len(src), len(zbuf.Bytes())) // aes src = pKCS7Padding(zbuf.Bytes(), aes.BlockSize) @@ -57,8 +56,6 @@ func (pc *Pcrypto) Encrypt(src []byte) ([]byte, error) { crypted := make([]byte, len(src)) blockMode.CryptBlocks(crypted, src) - fmt.Println("aes,src,en", len(src), len(crypted)) - // base64 return []byte(base64.StdEncoding.EncodeToString(crypted)), nil } @@ -87,7 +84,10 @@ func (pc *Pcrypto) Decrypt(str []byte) ([]byte, error) { // gunzip zbuf := bytes.NewBuffer(decryptText) - zrd, _ := gzip.NewReader(zbuf) + zrd, err := gzip.NewReader(zbuf) + if err != nil { + return nil, err + } defer zrd.Close() data, _ = ioutil.ReadAll(zrd) From bc176b90f1ab9f633971e8b051db01802c75e364 Mon Sep 17 00:00:00 2001 From: fatedier Date: Tue, 5 Apr 2016 17:18:21 +0800 Subject: [PATCH 12/14] all: change passwd to auth_token and improve authentication --- conf/frpc.ini | 3 ++- conf/frps.ini | 4 ++-- src/frp/cmd/frpc/control.go | 6 +++++- src/frp/cmd/frps/control.go | 16 ++++++++++++---- src/frp/models/client/client.go | 12 +++++++++--- src/frp/models/client/config.go | 15 ++++++++++----- src/frp/models/consts/consts.go | 1 + src/frp/models/msg/msg.go | 3 ++- src/frp/models/server/config.go | 4 ++-- src/frp/models/server/server.go | 18 ++++++++++-------- src/frp/utils/pcrypto/pcrypto.go | 8 ++++++++ 11 files changed, 63 insertions(+), 27 deletions(-) diff --git a/conf/frpc.ini b/conf/frpc.ini index 50a37604..2f48a80c 100644 --- a/conf/frpc.ini +++ b/conf/frpc.ini @@ -6,10 +6,11 @@ server_port = 7000 log_file = console # debug, info, warn, error log_level = debug +# for authentication +auth_token = 123 # test1 is the proxy name same as server's configuration [test1] -passwd = 123 local_ip = 127.0.0.1 local_port = 22 # true or false, if true, messages between frps and frpc will be encrypted, default is false diff --git a/conf/frps.ini b/conf/frps.ini index 0358a7ad..c410410d 100644 --- a/conf/frps.ini +++ b/conf/frps.ini @@ -7,8 +7,8 @@ log_file = console # debug, info, warn, error log_level = debug -# test1 is the proxy name, client will use this name and passwd to connect to server +# test1 is the proxy name, client will use this name and auth_token to connect to server [test1] -passwd = 123 +auth_token = 123 bind_addr = 0.0.0.0 listen_port = 6000 diff --git a/src/frp/cmd/frpc/control.go b/src/frp/cmd/frpc/control.go index 3ca8bada..06a4fdae 100644 --- a/src/frp/cmd/frpc/control.go +++ b/src/frp/cmd/frpc/control.go @@ -26,6 +26,7 @@ import ( "frp/models/msg" "frp/utils/conn" "frp/utils/log" + "frp/utils/pcrypto" ) func ControlProcess(cli *client.ProxyClient, wait *sync.WaitGroup) { @@ -130,11 +131,14 @@ func loginToServer(cli *client.ProxyClient) (c *conn.Conn, err error) { return } + nowTime := time.Now().Unix() + authKey := pcrypto.GetAuthKey(cli.Name + cli.AuthToken + fmt.Sprintf("%d", nowTime)) req := &msg.ControlReq{ Type: consts.NewCtlConn, ProxyName: cli.Name, - Passwd: cli.Passwd, + AuthKey: authKey, UseEncryption: cli.UseEncryption, + Timestamp: nowTime, } buf, _ := json.Marshal(req) err = c.Write(string(buf) + "\n") diff --git a/src/frp/cmd/frps/control.go b/src/frp/cmd/frps/control.go index dc2eb53c..67cd6428 100644 --- a/src/frp/cmd/frps/control.go +++ b/src/frp/cmd/frps/control.go @@ -25,6 +25,7 @@ import ( "frp/models/server" "frp/utils/conn" "frp/utils/log" + "frp/utils/pcrypto" ) func ProcessControlConn(l *conn.Listener) { @@ -197,16 +198,23 @@ func doLogin(req *msg.ControlReq, c *conn.Conn) (ret int64, info string) { return } - // check password - if req.Passwd != s.Passwd { - info = fmt.Sprintf("ProxyName [%s], password is not correct", req.ProxyName) + // check authKey + nowTime := time.Now().Unix() + authKey := pcrypto.GetAuthKey(req.ProxyName + s.AuthToken + fmt.Sprintf("%d", req.Timestamp)) + // authKey avaiable in 15 minutes + if nowTime-req.Timestamp > 15*60 { + info = fmt.Sprintf("ProxyName [%s], authorization timeout", req.ProxyName) + log.Warn(info) + return + } else if req.AuthKey != authKey { + info = fmt.Sprintf("ProxyName [%s], authorization failed", req.ProxyName) log.Warn(info) return } // control conn if req.Type == consts.NewCtlConn { - if s.Status != consts.Idle { + if s.Status == consts.Working { info = fmt.Sprintf("ProxyName [%s], already in use", req.ProxyName) log.Warn(info) return diff --git a/src/frp/models/client/client.go b/src/frp/models/client/client.go index 8310610e..b0b947b8 100644 --- a/src/frp/models/client/client.go +++ b/src/frp/models/client/client.go @@ -16,16 +16,19 @@ package client import ( "encoding/json" + "fmt" + "time" "frp/models/consts" "frp/models/msg" "frp/utils/conn" "frp/utils/log" + "frp/utils/pcrypto" ) type ProxyClient struct { Name string - Passwd string + AuthToken string LocalIp string LocalPort int64 UseEncryption bool @@ -52,10 +55,13 @@ func (p *ProxyClient) GetRemoteConn(addr string, port int64) (c *conn.Conn, err return } + nowTime := time.Now().Unix() + authKey := pcrypto.GetAuthKey(p.Name + p.AuthToken + fmt.Sprintf("%d", nowTime)) req := &msg.ControlReq{ Type: consts.NewWorkConn, ProxyName: p.Name, - Passwd: p.Passwd, + AuthKey: authKey, + Timestamp: nowTime, } buf, _ := json.Marshal(req) @@ -83,7 +89,7 @@ func (p *ProxyClient) StartTunnel(serverAddr string, serverPort int64) (err erro log.Debug("Join two connections, (l[%s] r[%s]) (l[%s] r[%s])", localConn.GetLocalAddr(), localConn.GetRemoteAddr(), remoteConn.GetLocalAddr(), remoteConn.GetRemoteAddr()) if p.UseEncryption { - go conn.JoinMore(localConn, remoteConn, p.Passwd) + go conn.JoinMore(localConn, remoteConn, p.AuthToken) } else { go conn.Join(localConn, remoteConn) } diff --git a/src/frp/models/client/config.go b/src/frp/models/client/config.go index 1e947430..3c09c751 100644 --- a/src/frp/models/client/config.go +++ b/src/frp/models/client/config.go @@ -69,6 +69,14 @@ func LoadConf(confFile string) (err error) { LogLevel = tmpStr } + var authToken string + tmpStr, ok = conf.Get("common", "auth_token") + if ok { + authToken = tmpStr + } else { + return fmt.Errorf("auth_token not found") + } + // proxies for name, section := range conf { if name != "common" { @@ -76,11 +84,8 @@ func LoadConf(confFile string) (err error) { // name proxyClient.Name = name - // passwd - proxyClient.Passwd, ok = section["passwd"] - if !ok { - return fmt.Errorf("Parse ini file error: proxy [%s] no passwd found", proxyClient.Name) - } + // auth_token + proxyClient.AuthToken = authToken // local_ip proxyClient.LocalIp, ok = section["local_ip"] diff --git a/src/frp/models/consts/consts.go b/src/frp/models/consts/consts.go index 342046e1..7bb09443 100644 --- a/src/frp/models/consts/consts.go +++ b/src/frp/models/consts/consts.go @@ -18,6 +18,7 @@ package consts const ( Idle = iota Working + Closed ) // msg type diff --git a/src/frp/models/msg/msg.go b/src/frp/models/msg/msg.go index 5bc21ed2..d1b57ad1 100644 --- a/src/frp/models/msg/msg.go +++ b/src/frp/models/msg/msg.go @@ -23,8 +23,9 @@ type GeneralRes struct { type ControlReq struct { Type int64 `json:"type"` ProxyName string `json:"proxy_name,omitempty"` - Passwd string `json:"passwd, omitempty"` + AuthKey string `json:"auth_key, omitempty"` UseEncryption bool `json:"use_encryption, omitempty"` + Timestamp int64 `json:"timestamp, omitempty"` } type ControlRes struct { diff --git a/src/frp/models/server/config.go b/src/frp/models/server/config.go index b2eb63f4..23fd9699 100644 --- a/src/frp/models/server/config.go +++ b/src/frp/models/server/config.go @@ -75,9 +75,9 @@ func LoadConf(confFile string) (err error) { proxyServer := &ProxyServer{} proxyServer.Name = name - proxyServer.Passwd, ok = section["passwd"] + proxyServer.AuthToken, ok = section["auth_token"] if !ok { - return fmt.Errorf("Parse ini file error: proxy [%s] no passwd found", proxyServer.Name) + return fmt.Errorf("Parse ini file error: proxy [%s] no auth_token found", proxyServer.Name) } proxyServer.BindAddr, ok = section["bind_addr"] diff --git a/src/frp/models/server/server.go b/src/frp/models/server/server.go index 8f285d05..d6e06daf 100644 --- a/src/frp/models/server/server.go +++ b/src/frp/models/server/server.go @@ -26,7 +26,7 @@ import ( type ProxyServer struct { Name string - Passwd string + AuthToken string UseEncryption bool BindAddr string ListenPort int64 @@ -135,7 +135,7 @@ func (p *ProxyServer) Start() (err error) { userConn.GetLocalAddr(), userConn.GetRemoteAddr()) if p.UseEncryption { - go conn.JoinMore(userConn, workConn, p.Passwd) + go conn.JoinMore(userConn, workConn, p.AuthToken) } else { go conn.Join(userConn, workConn) } @@ -147,13 +147,15 @@ func (p *ProxyServer) Start() (err error) { func (p *ProxyServer) Close() { p.Lock() - p.Status = consts.Idle - if p.listener != nil { - p.listener.Close() + if p.Status != consts.Closed { + p.Status = consts.Closed + if p.listener != nil { + p.listener.Close() + } + close(p.ctlMsgChan) + close(p.workConnChan) + p.userConnList = list.New() } - close(p.ctlMsgChan) - close(p.workConnChan) - p.userConnList = list.New() p.Unlock() } diff --git a/src/frp/utils/pcrypto/pcrypto.go b/src/frp/utils/pcrypto/pcrypto.go index 2e8ba928..a4772a82 100644 --- a/src/frp/utils/pcrypto/pcrypto.go +++ b/src/frp/utils/pcrypto/pcrypto.go @@ -19,6 +19,7 @@ import ( "compress/gzip" "crypto/aes" "crypto/cipher" + "crypto/md5" "encoding/base64" "encoding/hex" "errors" @@ -105,3 +106,10 @@ func pKCS7UnPadding(origData []byte) []byte { unpadding := int(origData[length-1]) return origData[:(length - unpadding)] } + +func GetAuthKey(str string) (authKey string) { + md5Ctx := md5.New() + md5Ctx.Write([]byte(str)) + md5Str := md5Ctx.Sum(nil) + return hex.EncodeToString(md5Str) +} From d091e0eac9b17523ccdbd0550c8365070adc5903 Mon Sep 17 00:00:00 2001 From: fatedier Date: Wed, 6 Apr 2016 11:43:50 +0800 Subject: [PATCH 13/14] doc: update --- README.md | 12 +++++++++++- README_zh.md | 40 ++++++++++++++++++++++++++++++++++++++++ doc/quick_start_en.md | 7 +++++-- doc/quick_start_zh.md | 7 +++++-- 4 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 README_zh.md diff --git a/README.md b/README.md index 14e81ec0..3a394563 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,17 @@ [![Build Status](https://travis-ci.org/fatedier/frp.svg)](https://travis-ci.org/fatedier/frp) +[README](README.md) | [中文文档](README_zh.md) + ## What is frp? frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet. ## Status -frp is under development and you can try it with available version 0.3.0. +frp is under development and you can try it with latest release version.Master branch for releasing stable version when dev branch for developing. + +**We may change any protocol and can't promise backward compatible before version 1.x.** ## Quick Start @@ -31,3 +35,9 @@ Interested in getting involved? We would love to help you! For simple bug fixes, just submit a PR with the fix and we can discuss the fix directly in the PR. If the fix is more complex, start with an issue. If you have some wanderful ideas, send email to fatedier@gmail.com. + +## Contributors + +* [fatedier](https://github.com/fatedier) +* [Hurricanezwf](https://github.com/Hurricanezwf) +* [vashstorm](https://github.com/vashstorm) diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 00000000..e5dcd2be --- /dev/null +++ b/README_zh.md @@ -0,0 +1,40 @@ +# frp + +[![Build Status](https://travis-ci.org/fatedier/frp.svg)](https://travis-ci.org/fatedier/frp) + +[README](README.md) | [中文文档](README_zh.md) + +>frp 是一个高性能的反向代理应用,可以帮助你轻松的进行内网穿透,对外网提供服务。 + +## 开发状态 + +frp 目前正在前期开发阶段,master分支用于发布稳定版本,dev分支用于开发,您可以尝试下载最新的 release 版本进行测试。 + +**在 1.x 版本以前,交互协议都可能会被改变,不能保证向后兼容。** + +## 快速开始 + +[QuickStart](doc/quick_start_en.md) | [使用文档](doc/quick_start_zh.md) + +## 架构 + +![architecture](doc/pic/architecture.png) + +## frp 的作用? + +* 利用处于内网或防火墙后的机器,对外网环境提供http服务。(针对http的优化正在开发中) +* 利用处于内网或防火墙后的机器,对外网环境提供tcp服务。 +* 可查看通过代理的所有http请求和响应信息。(待开发) + +## 贡献代码 + +如果您对这个项目感兴趣,并且想要参与其中,我们非常欢迎! + +* 如果您需要提交问题,可以通过 [issue](https://github.com/fatedier/frp/issues) 来完成。 +* 如果您有新的功能需求,可以反馈至 fatedier@gmail.com 共同讨论。 + +## 贡献者 + +* [fatedier](https://github.com/fatedier) +* [Hurricanezwf](https://github.com/Hurricanezwf) +* [vashstorm](https://github.com/vashstorm) diff --git a/doc/quick_start_en.md b/doc/quick_start_en.md index 46fa3c22..6b2a00c8 100644 --- a/doc/quick_start_en.md +++ b/doc/quick_start_en.md @@ -44,7 +44,7 @@ log_level = info # test is the custom name of proxy and there can be many proxies with unique name in one configure file [test] -passwd = 123 +auth_token = 123 bind_addr = 0.0.0.0 # finally we connect to server A by this port listen_port = 6000 @@ -59,10 +59,13 @@ server_addr = x.x.x.x server_port = 7000 log_file = ./frpc.log log_level = info +# for authentication +auth_token = 123 # test is proxy name same with configure in frps.ini [test] -passwd = 123 # local port which need to be transferred local_port = 22 +# if use_encryption equals true, messages between frpc and frps will be encrypted, default is false +use_encryption = true ``` diff --git a/doc/quick_start_zh.md b/doc/quick_start_zh.md index 61fb3bda..f48b55d7 100644 --- a/doc/quick_start_zh.md +++ b/doc/quick_start_zh.md @@ -42,7 +42,7 @@ log_level = info # test 为代理的自定义名称,可以有多个,不能重复,和frpc中名称对应 [test] -passwd = 123 +auth_token = 123 bind_addr = 0.0.0.0 # 最后将通过此端口访问后端服务 listen_port = 6000 @@ -57,10 +57,13 @@ server_addr = x.x.x.x server_port = 7000 log_file = ./frpc.log log_level = info +# 用于身份验证 +auth_token = 123 # test需要和 frps.ini 中配置一致 [test] -passwd = 123 # 需要转发的本地端口 local_port = 22 +# 启用加密,frpc与frps之间通信加密,默认为 false +use_encryption = true ``` From 6a0d6035cb7c4de5ee580409212da3ca63cf2b72 Mon Sep 17 00:00:00 2001 From: fatedier Date: Wed, 6 Apr 2016 11:51:12 +0800 Subject: [PATCH 14/14] doc: typo --- README.md | 5 ++--- README_zh.md | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3a394563..2ed7ffc7 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,8 @@ Read the [QuickStart](doc/quick_start_en.md) | [使用文档](doc/quick_start_zh Interested in getting involved? We would love to help you! -For simple bug fixes, just submit a PR with the fix and we can discuss the fix directly in the PR. If the fix is more complex, start with an issue. - -If you have some wanderful ideas, send email to fatedier@gmail.com. +* Take a look at our [issues list](https://github.com/fatedier/frp/issues) and consider submitting a patch +* If you have some wanderful ideas, send email to fatedier@gmail.com. ## Contributors diff --git a/README_zh.md b/README_zh.md index e5dcd2be..4b272577 100644 --- a/README_zh.md +++ b/README_zh.md @@ -30,7 +30,7 @@ frp 目前正在前期开发阶段,master分支用于发布稳定版本,dev 如果您对这个项目感兴趣,并且想要参与其中,我们非常欢迎! -* 如果您需要提交问题,可以通过 [issue](https://github.com/fatedier/frp/issues) 来完成。 +* 如果您需要提交问题,可以通过 [issues](https://github.com/fatedier/frp/issues) 来完成。 * 如果您有新的功能需求,可以反馈至 fatedier@gmail.com 共同讨论。 ## 贡献者