Skip to content

Commit

Permalink
Release v0.3.0
Browse files Browse the repository at this point in the history
Release v0.3.0
  • Loading branch information
fatedier committed Apr 6, 2016
2 parents 90349a4 + 6a0d603 commit 2ba84d3
Show file tree
Hide file tree
Showing 20 changed files with 526 additions and 295 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ language: go

go:
- 1.4.2
- 1.5.1
- 1.5.3

install:
- make
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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/

Expand All @@ -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"]
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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

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 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

Expand All @@ -28,6 +32,11 @@ 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.
* 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

If you have some wanderful ideas, send email to fatedier@gmail.com.
* [fatedier](/~https://github.com/fatedier)
* [Hurricanezwf](/~https://github.com/Hurricanezwf)
* [vashstorm](/~https://github.com/vashstorm)
40 changes: 40 additions & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
@@ -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请求和响应信息。(待开发)

## 贡献代码

如果您对这个项目感兴趣,并且想要参与其中,我们非常欢迎!

* 如果您需要提交问题,可以通过 [issues](/~https://github.com/fatedier/frp/issues) 来完成。
* 如果您有新的功能需求,可以反馈至 fatedier@gmail.com 共同讨论。

## 贡献者

* [fatedier](/~https://github.com/fatedier)
* [Hurricanezwf](/~https://github.com/Hurricanezwf)
* [vashstorm](/~https://github.com/vashstorm)
5 changes: 4 additions & 1 deletion conf/frpc.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ 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
use_encryption = true
4 changes: 2 additions & 2 deletions conf/frps.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 5 additions & 2 deletions doc/quick_start_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
```
7 changes: 5 additions & 2 deletions doc/quick_start_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ log_level = info

# test 为代理的自定义名称,可以有多个,不能重复,和frpc中名称对应
[test]
passwd = 123
auth_token = 123
bind_addr = 0.0.0.0
# 最后将通过此端口访问后端服务
listen_port = 6000
Expand All @@ -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
```
155 changes: 86 additions & 69 deletions src/frp/cmd/frpc/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,66 +26,101 @@ import (
"frp/models/msg"
"frp/utils/conn"
"frp/utils/log"
"frp/utils/pcrypto"
)

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)
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
}
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")
}
continue

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
}

cli.StartTunnel(client.ServerAddr, client.ServerPort)
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
}
}
}

Expand All @@ -96,10 +131,14 @@ func loginToServer(cli *client.ProxyClient) (c *conn.Conn, err error) {
return
}

req := &msg.ClientCtlReq{
Type: consts.CtlConn,
ProxyName: cli.Name,
Passwd: cli.Passwd,
nowTime := time.Now().Unix()
authKey := pcrypto.GetAuthKey(cli.Name + cli.AuthToken + fmt.Sprintf("%d", nowTime))
req := &msg.ControlReq{
Type: consts.NewCtlConn,
ProxyName: cli.Name,
AuthKey: authKey,
UseEncryption: cli.UseEncryption,
Timestamp: nowTime,
}
buf, _ := json.Marshal(req)
err = c.Write(string(buf) + "\n")
Expand All @@ -115,53 +154,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()
}
}
heartBeatTimer = time.AfterFunc(time.Duration(client.HeartBeatTimeout)*time.Second, f)
defer heartBeatTimer.Stop()

clientCtlReq := &msg.ClientCtlReq{
Type: consts.CSHeartBeatReq,
ProxyName: "",
Passwd: "",
func heartbeatSender(c *conn.Conn, msgSendChan chan interface{}) {
heartbeatReq := &msg.ControlReq{
Type: consts.HeartbeatReq,
}
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
}
Expand Down
Loading

0 comments on commit 2ba84d3

Please sign in to comment.