Skip to content

Commit

Permalink
Merge pull request fatedier#1191 from fatedier/dev
Browse files Browse the repository at this point in the history
Bump version to v0.26.0
  • Loading branch information
fatedier authored Apr 10, 2019
2 parents a8ab4c5 + 12c5c55 commit 6a7efc8
Show file tree
Hide file tree
Showing 34 changed files with 1,179 additions and 41 deletions.
55 changes: 51 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Now it also try to support p2p connect.
* [Forward DNS query request](#forward-dns-query-request)
* [Forward unix domain socket](#forward-unix-domain-socket)
* [Expose a simple http file server](#expose-a-simple-http-file-server)
* [Enable HTTPS for local HTTP service](#enable-https-for-local-http-service)
* [Expose your service in security](#expose-your-service-in-security)
* [P2P Mode](#p2p-mode)
* [Features](#features)
Expand All @@ -44,6 +45,8 @@ Now it also try to support p2p connect.
* [Rewriting the Host Header](#rewriting-the-host-header)
* [Set Headers In HTTP Request](#set-headers-in-http-request)
* [Get Real IP](#get-real-ip)
* [HTTP X-Forwarded-For](#http-x-forwarded-for)
* [Proxy Protocol](#proxy-protocol)
* [Password protecting your web service](#password-protecting-your-web-service)
* [Custom subdomain names](#custom-subdomain-names)
* [URL routing](#url-routing)
Expand Down Expand Up @@ -243,11 +246,34 @@ Configure frps same as above.

2. Visit `http://x.x.x.x:6000/static/` by your browser, set correct user and password, so you can see files in `/tmp/file`.

### Enable HTTPS for local HTTP service

1. Start frpc with configurations:

```ini
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[test_htts2http]
type = https
custom_domains = test.yourdomain.com

plugin = https2http
plugin_local_addr = 127.0.0.1:80
plugin_crt_path = ./server.crt
plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
```

2. Visit `https://test.yourdomain.com`.

### Expose your service in security

For some services, if expose them to the public network directly will be a security risk.

**stcp(secret tcp)** help you create a proxy avoiding any one can access it.
**stcp(secret tcp)** helps you create a proxy avoiding any one can access it.

Configure frps same as above.

Expand Down Expand Up @@ -484,8 +510,6 @@ tcp_mux = false

### Support KCP Protocol

frp support kcp protocol since v0.12.0.

KCP is a fast and reliable protocol that can achieve the transmission effect of a reduction of the average latency by 30% to 40% and reduction of the maximum delay by a factor of three, at the cost of 10% to 20% more bandwidth wasted than TCP.

Using kcp in frp:
Expand Down Expand Up @@ -639,9 +663,32 @@ In this example, it will set header `X-From-Where: frp` to http request.

### Get Real IP

#### HTTP X-Forwarded-For

Features for http proxy only.

You can get user's real IP from http request header `X-Forwarded-For` and `X-Real-IP`.
You can get user's real IP from HTTP request header `X-Forwarded-For` and `X-Real-IP`.

#### Proxy Protocol

frp support Proxy Protocol to send user's real IP to local service. It support all types without UDP.

Here is an example for https service:

```ini
# frpc.ini
[web]
type = https
local_port = 443
custom_domains = test.yourdomain.com

# now v1 and v2 is supported
proxy_protocol_version = v2
```

You can enable Proxy Protocol support in nginx to parse user's real IP to http header `X-Real-IP`.

Then you can get it from HTTP request header in your local service.

### Password protecting your web service

Expand Down
62 changes: 60 additions & 2 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp
* [转发 DNS 查询请求](#转发-dns-查询请求)
* [转发 Unix域套接字](#转发-unix域套接字)
* [对外提供简单的文件访问服务](#对外提供简单的文件访问服务)
* [为本地 HTTP 服务启用 HTTPS](#为本地-http-服务启用-https)
* [安全地暴露内网服务](#安全地暴露内网服务)
* [点对点内网穿透](#点对点内网穿透)
* [功能说明](#功能说明)
Expand All @@ -40,6 +41,8 @@ frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp
* [修改 Host Header](#修改-host-header)
* [设置 HTTP 请求的 header](#设置-http-请求的-header)
* [获取用户真实 IP](#获取用户真实-ip)
* [HTTP X-Forwarded-For](#http-x-forwarded-for)
* [Proxy Protocol](#proxy-protocol)
* [通过密码保护你的 web 服务](#通过密码保护你的-web-服务)
* [自定义二级域名](#自定义二级域名)
* [URL 路由](#url-路由)
Expand Down Expand Up @@ -244,6 +247,33 @@ frps 的部署步骤同上。

2. 通过浏览器访问 `http://x.x.x.x:6000/static/` 来查看位于 `/tmp/file` 目录下的文件,会要求输入已设置好的用户名和密码。

### 为本地 HTTP 服务启用 HTTPS

通过 `https2http` 插件可以让本地 HTTP 服务转换成 HTTPS 服务对外提供。

1. 启用 frpc,启用 `https2http` 插件,配置如下:

```ini
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[test_htts2http]
type = https
custom_domains = test.yourdomain.com

plugin = https2http
plugin_local_addr = 127.0.0.1:80

# HTTPS 证书相关的配置
plugin_crt_path = ./server.crt
plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
```

2. 通过浏览器访问 `https://test.yourdomain.com` 即可。

### 安全地暴露内网服务

对于某些服务来说如果直接暴露于公网上将会存在安全隐患。
Expand Down Expand Up @@ -514,7 +544,7 @@ tcp_mux = false

### 底层通信可选 kcp 协议

从 v0.12.0 版本开始,底层通信协议支持选择 kcp 协议,在弱网环境下传输效率提升明显,但是会有一些额外的流量消耗。
底层通信协议支持选择 kcp 协议,在弱网环境下传输效率提升明显,但是会有一些额外的流量消耗。

开启 kcp 协议支持:

Expand Down Expand Up @@ -566,6 +596,7 @@ tcp_mux = false
### 负载均衡

可以将多个相同类型的 proxy 加入到同一个 group 中,从而实现负载均衡的功能。

目前只支持 tcp 类型的 proxy。

```ini
Expand Down Expand Up @@ -668,7 +699,34 @@ header_X-From-Where = frp

### 获取用户真实 IP

目前只有 **http** 类型的代理支持这一功能,可以通过用户请求的 header 中的 `X-Forwarded-For``X-Real-IP` 来获取用户真实 IP。
#### HTTP X-Forwarded-For

目前只有 **http** 类型的代理支持这一功能,可以通过用户请求的 header 中的 `X-Forwarded-For` 来获取用户真实 IP,默认启用。

#### Proxy Protocol

frp 支持通过 **Proxy Protocol** 协议来传递经过 frp 代理的请求的真实 IP,此功能支持所有以 TCP 为底层协议的类型,不支持 UDP。

**Proxy Protocol** 功能启用后,frpc 在和本地服务建立连接后,会先发送一段 **Proxy Protocol** 的协议内容给本地服务,本地服务通过解析这一内容可以获得访问用户的真实 IP。所以不仅仅是 HTTP 服务,任何的 TCP 服务,只要支持这一协议,都可以获得用户的真实 IP 地址。

需要注意的是,在代理配置中如果要启用此功能,需要本地的服务能够支持 **Proxy Protocol** 这一协议,目前 nginx 和 haproxy 都能够很好的支持。

这里以 https 类型为例:

```ini
# frpc.ini
[web]
type = https
local_port = 443
custom_domains = test.yourdomain.com

# 目前支持 v1 和 v2 两个版本的 proxy protocol 协议。
proxy_protocol_version = v2
```

只需要在代理配置中增加一行 `proxy_protocol_version = v2` 即可开启此功能。

本地的 https 服务可以通过在 nginx 的配置中启用 **Proxy Protocol** 的解析并将结果设置在 `X-Real-IP` 这个 Header 中就可以在自己的 Web 服务中通过 `X-Real-IP` 获取到用户的真实 IP。

### 通过密码保护你的 web 服务

Expand Down
9 changes: 8 additions & 1 deletion client/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (ctl *Control) HandleReqWorkConn(inMsg *msg.ReqWorkConn) {
workConn.AddLogPrefix(startMsg.ProxyName)

// dispatch this work connection to related proxy
ctl.pm.HandleWorkConn(startMsg.ProxyName, workConn)
ctl.pm.HandleWorkConn(startMsg.ProxyName, workConn, &startMsg)
}

func (ctl *Control) HandleNewProxyResp(inMsg *msg.NewProxyResp) {
Expand All @@ -148,6 +148,9 @@ func (ctl *Control) HandleNewProxyResp(inMsg *msg.NewProxyResp) {
func (ctl *Control) Close() error {
ctl.pm.Close()
ctl.conn.Close()
if ctl.session != nil {
ctl.session.Close()
}
return nil
}

Expand Down Expand Up @@ -202,6 +205,7 @@ func (ctl *Control) reader() {
return
} else {
ctl.Warn("read error: %v", err)
ctl.conn.Close()
return
}
} else {
Expand Down Expand Up @@ -300,6 +304,9 @@ func (ctl *Control) worker() {
ctl.vm.Close()

close(ctl.closedDoneCh)
if ctl.session != nil {
ctl.session.Close()
}
return
}
}
Expand Down
58 changes: 45 additions & 13 deletions client/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@ import (
frpIo "github.com/fatedier/golib/io"
"github.com/fatedier/golib/pool"
fmux "github.com/hashicorp/yamux"
pp "github.com/pires/go-proxyproto"
)

// Proxy defines how to handle work connections for different proxy type.
type Proxy interface {
Run() error

// InWorkConn accept work connections registered to server.
InWorkConn(conn frpNet.Conn)
InWorkConn(frpNet.Conn, *msg.StartWorkConn)

Close()
log.Logger
Expand Down Expand Up @@ -119,9 +120,9 @@ func (pxy *TcpProxy) Close() {
}
}

func (pxy *TcpProxy) InWorkConn(conn frpNet.Conn) {
func (pxy *TcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(g.GlbClientCfg.Token))
[]byte(g.GlbClientCfg.Token), m)
}

// HTTP
Expand All @@ -148,9 +149,9 @@ func (pxy *HttpProxy) Close() {
}
}

func (pxy *HttpProxy) InWorkConn(conn frpNet.Conn) {
func (pxy *HttpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(g.GlbClientCfg.Token))
[]byte(g.GlbClientCfg.Token), m)
}

// HTTPS
Expand All @@ -177,9 +178,9 @@ func (pxy *HttpsProxy) Close() {
}
}

func (pxy *HttpsProxy) InWorkConn(conn frpNet.Conn) {
func (pxy *HttpsProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(g.GlbClientCfg.Token))
[]byte(g.GlbClientCfg.Token), m)
}

// STCP
Expand All @@ -206,9 +207,9 @@ func (pxy *StcpProxy) Close() {
}
}

func (pxy *StcpProxy) InWorkConn(conn frpNet.Conn) {
func (pxy *StcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(g.GlbClientCfg.Token))
[]byte(g.GlbClientCfg.Token), m)
}

// XTCP
Expand All @@ -235,7 +236,7 @@ func (pxy *XtcpProxy) Close() {
}
}

func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn) {
func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
defer conn.Close()
var natHoleSidMsg msg.NatHoleSid
err := msg.ReadMsgInto(conn, &natHoleSidMsg)
Expand Down Expand Up @@ -353,7 +354,7 @@ func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn) {
}

HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf,
frpNet.WrapConn(muxConn), []byte(pxy.cfg.Sk))
frpNet.WrapConn(muxConn), []byte(pxy.cfg.Sk), m)
}

func (pxy *XtcpProxy) sendDetectMsg(addr string, port int, laddr *net.UDPAddr, content []byte) (err error) {
Expand Down Expand Up @@ -415,7 +416,7 @@ func (pxy *UdpProxy) Close() {
}
}

func (pxy *UdpProxy) InWorkConn(conn frpNet.Conn) {
func (pxy *UdpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
pxy.Info("incoming a new work connection for udp proxy, %s", conn.RemoteAddr().String())
// close resources releated with old workConn
pxy.Close()
Expand Down Expand Up @@ -482,7 +483,7 @@ func (pxy *UdpProxy) InWorkConn(conn frpNet.Conn) {

// Common handler for tcp work connections.
func HandleTcpWorkConnection(localInfo *config.LocalSvrConf, proxyPlugin plugin.Plugin,
baseInfo *config.BaseProxyConf, workConn frpNet.Conn, encKey []byte) {
baseInfo *config.BaseProxyConf, workConn frpNet.Conn, encKey []byte, m *msg.StartWorkConn) {

var (
remote io.ReadWriteCloser
Expand Down Expand Up @@ -518,6 +519,37 @@ func HandleTcpWorkConnection(localInfo *config.LocalSvrConf, proxyPlugin plugin.

workConn.Debug("join connections, localConn(l[%s] r[%s]) workConn(l[%s] r[%s])", localConn.LocalAddr().String(),
localConn.RemoteAddr().String(), workConn.LocalAddr().String(), workConn.RemoteAddr().String())

// check if we need to send proxy protocol info
if baseInfo.ProxyProtocolVersion != "" {
if m.SrcAddr != "" && m.SrcPort != 0 {
if m.DstAddr == "" {
m.DstAddr = "127.0.0.1"
}
h := &pp.Header{
Command: pp.PROXY,
SourceAddress: net.ParseIP(m.SrcAddr),
SourcePort: m.SrcPort,
DestinationAddress: net.ParseIP(m.DstAddr),
DestinationPort: m.DstPort,
}

if h.SourceAddress.To16() == nil {
h.TransportProtocol = pp.TCPv4
} else {
h.TransportProtocol = pp.TCPv6
}

if baseInfo.ProxyProtocolVersion == "v1" {
h.Version = 1
} else if baseInfo.ProxyProtocolVersion == "v2" {
h.Version = 2
}

h.WriteTo(localConn)
}
}

frpIo.Join(localConn, remote)
workConn.Debug("join connections closed")
}
Expand Down
4 changes: 2 additions & 2 deletions client/proxy/proxy_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ func (pm *ProxyManager) Close() {
pm.proxies = make(map[string]*ProxyWrapper)
}

func (pm *ProxyManager) HandleWorkConn(name string, workConn frpNet.Conn) {
func (pm *ProxyManager) HandleWorkConn(name string, workConn frpNet.Conn, m *msg.StartWorkConn) {
pm.mu.RLock()
pw, ok := pm.proxies[name]
pm.mu.RUnlock()
if ok {
pw.InWorkConn(workConn)
pw.InWorkConn(workConn, m)
} else {
workConn.Close()
}
Expand Down
Loading

0 comments on commit 6a7efc8

Please sign in to comment.