Skip to content

Commit

Permalink
Merge pull request #1349 from fatedier/dev
Browse files Browse the repository at this point in the history
bump version to v0.28.0
  • Loading branch information
fatedier authored Aug 1, 2019
2 parents e611c44 + 30cb0a3 commit 6451583
Show file tree
Hide file tree
Showing 17 changed files with 346 additions and 118 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,8 @@ This feature is fit for a large number of short connections.
### Load balancing
Load balancing is supported by `group`.
This feature is available only for type `tcp` now.
This feature is available only for type `tcp` and `http` now.
```ini
# frpc.ini
Expand All @@ -583,6 +584,10 @@ group_key = 123
Proxies in same group will accept connections from port 80 randomly.
For `tcp` type, `remote_port` in one group shoud be same.
For `http` type, `custom_domains, subdomain, locations` shoud be same.
### Health Check
Health check feature can help you achieve high availability with load balancing.
Expand Down
10 changes: 6 additions & 4 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp
* [通过 ssh 访问公司内网机器](#通过-ssh-访问公司内网机器)
* [通过自定义域名访问部署于内网的 web 服务](#通过自定义域名访问部署于内网的-web-服务)
* [转发 DNS 查询请求](#转发-dns-查询请求)
* [转发 Unix域套接字](#转发-unix域套接字)
* [转发 Unix 域套接字](#转发-unix-域套接字)
* [对外提供简单的文件访问服务](#对外提供简单的文件访问服务)
* [为本地 HTTP 服务启用 HTTPS](#为本地-http-服务启用-https)
* [安全地暴露内网服务](#安全地暴露内网服务)
Expand Down Expand Up @@ -194,7 +194,7 @@ DNS 查询请求通常使用 UDP 协议,frp 支持对内网 UDP 服务的穿

`dig @x.x.x.x -p 6000 www.google.com`

### 转发 Unix域套接字
### 转发 Unix 域套接字

通过 tcp 端口访问内网的 unix域套接字(例如和 docker daemon 通信)。

Expand Down Expand Up @@ -597,7 +597,7 @@ tcp_mux = false

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

目前只支持 tcp 类型的 proxy。
目前只支持 TCP 和 HTTP 类型的 proxy。

```ini
# frpc.ini
Expand All @@ -618,7 +618,9 @@ group_key = 123

用户连接 frps 服务器的 80 端口,frps 会将接收到的用户连接随机分发给其中一个存活的 proxy。这样可以在一台 frpc 机器挂掉后仍然有其他节点能够提供服务。

要求 `group_key` 相同,做权限验证,且 `remote_port` 相同。
TCP 类型代理要求 `group_key` 相同,做权限验证,且 `remote_port` 相同。

HTTP 类型代理要求 `group_key, custom_domains 或 subdomain 和 locations` 相同。

### 健康检查

Expand Down
2 changes: 2 additions & 0 deletions client/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ func (svr *Service) Run() error {
if g.GlbClientCfg.LoginFailExit {
return err
} else {
conn.Close()
session.Close()
time.Sleep(10 * time.Second)
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion conf/frpc_full.ini
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ tls_enable = true
# specify a dns server, so frpc will use this instead of default one
# dns_server = 8.8.8.8

# proxy names you want to start divided by ','
# proxy names you want to start seperated by ','
# default is empty, means all proxies
# start = ssh,dns

Expand Down
5 changes: 4 additions & 1 deletion server/controller/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ type ResourceController struct {
// Tcp Group Controller
TcpGroupCtl *group.TcpGroupCtl

// HTTP Group Controller
HTTPGroupCtl *group.HTTPGroupController

// Manage all tcp ports
TcpPortManager *ports.PortManager

Expand All @@ -38,7 +41,7 @@ type ResourceController struct {
// For http proxies, forwarding http requests
HttpReverseProxy *vhost.HttpReverseProxy

// For https proxies, route requests to different clients by hostname and other infomation
// For https proxies, route requests to different clients by hostname and other information
VhostHttpsMuxer *vhost.HttpsMuxer

// Controller for nat hole connections
Expand Down
1 change: 1 addition & 0 deletions server/group/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ var (
ErrGroupParamsInvalid = errors.New("group params invalid")
ErrListenerClosed = errors.New("group listener closed")
ErrGroupDifferentPort = errors.New("group should have same remote port")
ErrProxyRepeated = errors.New("group proxy repeated")
)
157 changes: 157 additions & 0 deletions server/group/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package group

import (
"fmt"
"sync"
"sync/atomic"

frpNet "github.com/fatedier/frp/utils/net"

"github.com/fatedier/frp/utils/vhost"
)

type HTTPGroupController struct {
groups map[string]*HTTPGroup

vhostRouter *vhost.VhostRouters

mu sync.Mutex
}

func NewHTTPGroupController(vhostRouter *vhost.VhostRouters) *HTTPGroupController {
return &HTTPGroupController{
groups: make(map[string]*HTTPGroup),
vhostRouter: vhostRouter,
}
}

func (ctl *HTTPGroupController) Register(proxyName, group, groupKey string,
routeConfig vhost.VhostRouteConfig) (err error) {

indexKey := httpGroupIndex(group, routeConfig.Domain, routeConfig.Location)
ctl.mu.Lock()
g, ok := ctl.groups[indexKey]
if !ok {
g = NewHTTPGroup(ctl)
ctl.groups[indexKey] = g
}
ctl.mu.Unlock()

return g.Register(proxyName, group, groupKey, routeConfig)
}

func (ctl *HTTPGroupController) UnRegister(proxyName, group, domain, location string) {
indexKey := httpGroupIndex(group, domain, location)
ctl.mu.Lock()
defer ctl.mu.Unlock()
g, ok := ctl.groups[indexKey]
if !ok {
return
}

isEmpty := g.UnRegister(proxyName)
if isEmpty {
delete(ctl.groups, indexKey)
}
}

type HTTPGroup struct {
group string
groupKey string
domain string
location string

createFuncs map[string]vhost.CreateConnFunc
pxyNames []string
index uint64
ctl *HTTPGroupController
mu sync.RWMutex
}

func NewHTTPGroup(ctl *HTTPGroupController) *HTTPGroup {
return &HTTPGroup{
createFuncs: make(map[string]vhost.CreateConnFunc),
pxyNames: make([]string, 0),
ctl: ctl,
}
}

func (g *HTTPGroup) Register(proxyName, group, groupKey string,
routeConfig vhost.VhostRouteConfig) (err error) {

g.mu.Lock()
defer g.mu.Unlock()
if len(g.createFuncs) == 0 {
// the first proxy in this group
tmp := routeConfig // copy object
tmp.CreateConnFn = g.createConn
err = g.ctl.vhostRouter.Add(routeConfig.Domain, routeConfig.Location, &tmp)
if err != nil {
return
}

g.group = group
g.groupKey = groupKey
g.domain = routeConfig.Domain
g.location = routeConfig.Location
} else {
if g.group != group || g.domain != routeConfig.Domain || g.location != routeConfig.Location {
err = ErrGroupParamsInvalid
return
}
if g.groupKey != groupKey {
err = ErrGroupAuthFailed
return
}
}
if _, ok := g.createFuncs[proxyName]; ok {
err = ErrProxyRepeated
return
}
g.createFuncs[proxyName] = routeConfig.CreateConnFn
g.pxyNames = append(g.pxyNames, proxyName)
return nil
}

func (g *HTTPGroup) UnRegister(proxyName string) (isEmpty bool) {
g.mu.Lock()
defer g.mu.Unlock()
delete(g.createFuncs, proxyName)
for i, name := range g.pxyNames {
if name == proxyName {
g.pxyNames = append(g.pxyNames[:i], g.pxyNames[i+1:]...)
break
}
}

if len(g.createFuncs) == 0 {
isEmpty = true
g.ctl.vhostRouter.Del(g.domain, g.location)
}
return
}

func (g *HTTPGroup) createConn(remoteAddr string) (frpNet.Conn, error) {
var f vhost.CreateConnFunc
newIndex := atomic.AddUint64(&g.index, 1)

g.mu.RLock()
group := g.group
domain := g.domain
location := g.location
if len(g.pxyNames) > 0 {
name := g.pxyNames[int(newIndex)%len(g.pxyNames)]
f, _ = g.createFuncs[name]
}
g.mu.RUnlock()

if f == nil {
return nil, fmt.Errorf("no CreateConnFunc for http group [%s], domain [%s], location [%s]", group, domain, location)
}

return f(remoteAddr)
}

func httpGroupIndex(group, domain, location string) string {
return fmt.Sprintf("%s_%s_%s", group, domain, location)
}
Loading

0 comments on commit 6451583

Please sign in to comment.