Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
企猫商务
frp
提交
6d78af61
F
frp
项目概览
企猫商务
/
frp
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
F
frp
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
6d78af61
编写于
4月 19, 2020
作者:
G
Guy Lewin
提交者:
GitHub
4月 20, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: group TCP mux proxies (#1765)
上级
7728e35c
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
253 addition
and
28 deletion
+253
-28
server/controller/resource.go
server/controller/resource.go
+3
-0
server/group/tcpmux.go
server/group/tcpmux.go
+218
-0
server/proxy/tcpmux.go
server/proxy/tcpmux.go
+12
-11
server/service.go
server/service.go
+20
-17
未找到文件。
server/controller/resource.go
浏览文件 @
6d78af61
...
...
@@ -34,6 +34,9 @@ type ResourceController struct {
// HTTP Group Controller
HTTPGroupCtl
*
group
.
HTTPGroupController
// TCP Mux Group Controller
TcpMuxGroupCtl
*
group
.
TcpMuxGroupCtl
// Manage all tcp ports
TcpPortManager
*
ports
.
PortManager
...
...
server/group/tcpmux.go
0 → 100644
浏览文件 @
6d78af61
// Copyright 2020 guylewin, guy@lewin.co.il
//
// 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
group
import
(
"context"
"fmt"
"net"
"sync"
"github.com/fatedier/frp/models/consts"
"github.com/fatedier/frp/utils/tcpmux"
"github.com/fatedier/frp/utils/vhost"
gerr
"github.com/fatedier/golib/errors"
)
// TcpMuxGroupCtl manage all TcpMuxGroups
type
TcpMuxGroupCtl
struct
{
groups
map
[
string
]
*
TcpMuxGroup
// portManager is used to manage port
tcpMuxHttpConnectMuxer
*
tcpmux
.
HttpConnectTcpMuxer
mu
sync
.
Mutex
}
// NewTcpMuxGroupCtl return a new TcpMuxGroupCtl
func
NewTcpMuxGroupCtl
(
tcpMuxHttpConnectMuxer
*
tcpmux
.
HttpConnectTcpMuxer
)
*
TcpMuxGroupCtl
{
return
&
TcpMuxGroupCtl
{
groups
:
make
(
map
[
string
]
*
TcpMuxGroup
),
tcpMuxHttpConnectMuxer
:
tcpMuxHttpConnectMuxer
,
}
}
// Listen is the wrapper for TcpMuxGroup's Listen
// If there are no group, we will create one here
func
(
tmgc
*
TcpMuxGroupCtl
)
Listen
(
multiplexer
string
,
group
string
,
groupKey
string
,
domain
string
,
ctx
context
.
Context
)
(
l
net
.
Listener
,
err
error
)
{
tmgc
.
mu
.
Lock
()
tcpMuxGroup
,
ok
:=
tmgc
.
groups
[
group
]
if
!
ok
{
tcpMuxGroup
=
NewTcpMuxGroup
(
tmgc
)
tmgc
.
groups
[
group
]
=
tcpMuxGroup
}
tmgc
.
mu
.
Unlock
()
switch
multiplexer
{
case
consts
.
HttpConnectTcpMultiplexer
:
return
tcpMuxGroup
.
HttpConnectListen
(
group
,
groupKey
,
domain
,
ctx
)
default
:
err
=
fmt
.
Errorf
(
"unknown multiplexer [%s]"
,
multiplexer
)
return
}
}
// RemoveGroup remove TcpMuxGroup from controller
func
(
tmgc
*
TcpMuxGroupCtl
)
RemoveGroup
(
group
string
)
{
tmgc
.
mu
.
Lock
()
defer
tmgc
.
mu
.
Unlock
()
delete
(
tmgc
.
groups
,
group
)
}
// TcpMuxGroup route connections to different proxies
type
TcpMuxGroup
struct
{
group
string
groupKey
string
domain
string
acceptCh
chan
net
.
Conn
index
uint64
tcpMuxLn
net
.
Listener
lns
[]
*
TcpMuxGroupListener
ctl
*
TcpMuxGroupCtl
mu
sync
.
Mutex
}
// NewTcpMuxGroup return a new TcpMuxGroup
func
NewTcpMuxGroup
(
ctl
*
TcpMuxGroupCtl
)
*
TcpMuxGroup
{
return
&
TcpMuxGroup
{
lns
:
make
([]
*
TcpMuxGroupListener
,
0
),
ctl
:
ctl
,
acceptCh
:
make
(
chan
net
.
Conn
),
}
}
// Listen will return a new TcpMuxGroupListener
// if TcpMuxGroup already has a listener, just add a new TcpMuxGroupListener to the queues
// otherwise, listen on the real address
func
(
tmg
*
TcpMuxGroup
)
HttpConnectListen
(
group
string
,
groupKey
string
,
domain
string
,
context
context
.
Context
)
(
ln
*
TcpMuxGroupListener
,
err
error
)
{
tmg
.
mu
.
Lock
()
defer
tmg
.
mu
.
Unlock
()
if
len
(
tmg
.
lns
)
==
0
{
// the first listener, listen on the real address
routeConfig
:=
&
vhost
.
VhostRouteConfig
{
Domain
:
domain
,
}
tcpMuxLn
,
errRet
:=
tmg
.
ctl
.
tcpMuxHttpConnectMuxer
.
Listen
(
context
,
routeConfig
)
if
errRet
!=
nil
{
return
nil
,
errRet
}
ln
=
newTcpMuxGroupListener
(
group
,
tmg
,
tcpMuxLn
.
Addr
())
tmg
.
group
=
group
tmg
.
groupKey
=
groupKey
tmg
.
domain
=
domain
tmg
.
tcpMuxLn
=
tcpMuxLn
tmg
.
lns
=
append
(
tmg
.
lns
,
ln
)
if
tmg
.
acceptCh
==
nil
{
tmg
.
acceptCh
=
make
(
chan
net
.
Conn
)
}
go
tmg
.
worker
()
}
else
{
// domain in the same group must be equal
if
tmg
.
group
!=
group
||
tmg
.
domain
!=
domain
{
return
nil
,
ErrGroupParamsInvalid
}
if
tmg
.
groupKey
!=
groupKey
{
return
nil
,
ErrGroupAuthFailed
}
ln
=
newTcpMuxGroupListener
(
group
,
tmg
,
tmg
.
lns
[
0
]
.
Addr
())
tmg
.
lns
=
append
(
tmg
.
lns
,
ln
)
}
return
}
// worker is called when the real tcp listener has been created
func
(
tmg
*
TcpMuxGroup
)
worker
()
{
for
{
c
,
err
:=
tmg
.
tcpMuxLn
.
Accept
()
if
err
!=
nil
{
return
}
err
=
gerr
.
PanicToError
(
func
()
{
tmg
.
acceptCh
<-
c
})
if
err
!=
nil
{
return
}
}
}
func
(
tmg
*
TcpMuxGroup
)
Accept
()
<-
chan
net
.
Conn
{
return
tmg
.
acceptCh
}
// CloseListener remove the TcpMuxGroupListener from the TcpMuxGroup
func
(
tmg
*
TcpMuxGroup
)
CloseListener
(
ln
*
TcpMuxGroupListener
)
{
tmg
.
mu
.
Lock
()
defer
tmg
.
mu
.
Unlock
()
for
i
,
tmpLn
:=
range
tmg
.
lns
{
if
tmpLn
==
ln
{
tmg
.
lns
=
append
(
tmg
.
lns
[
:
i
],
tmg
.
lns
[
i
+
1
:
]
...
)
break
}
}
if
len
(
tmg
.
lns
)
==
0
{
close
(
tmg
.
acceptCh
)
tmg
.
tcpMuxLn
.
Close
()
tmg
.
ctl
.
RemoveGroup
(
tmg
.
group
)
}
}
// TcpMuxGroupListener
type
TcpMuxGroupListener
struct
{
groupName
string
group
*
TcpMuxGroup
addr
net
.
Addr
closeCh
chan
struct
{}
}
func
newTcpMuxGroupListener
(
name
string
,
group
*
TcpMuxGroup
,
addr
net
.
Addr
)
*
TcpMuxGroupListener
{
return
&
TcpMuxGroupListener
{
groupName
:
name
,
group
:
group
,
addr
:
addr
,
closeCh
:
make
(
chan
struct
{}),
}
}
// Accept will accept connections from TcpMuxGroup
func
(
ln
*
TcpMuxGroupListener
)
Accept
()
(
c
net
.
Conn
,
err
error
)
{
var
ok
bool
select
{
case
<-
ln
.
closeCh
:
return
nil
,
ErrListenerClosed
case
c
,
ok
=
<-
ln
.
group
.
Accept
()
:
if
!
ok
{
return
nil
,
ErrListenerClosed
}
return
c
,
nil
}
}
func
(
ln
*
TcpMuxGroupListener
)
Addr
()
net
.
Addr
{
return
ln
.
addr
}
// Close close the listener
func
(
ln
*
TcpMuxGroupListener
)
Close
()
(
err
error
)
{
close
(
ln
.
closeCh
)
// remove self from TcpMuxGroup
ln
.
group
.
CloseListener
(
ln
)
return
}
server/proxy/tcpmux.go
浏览文件 @
6d78af61
...
...
@@ -16,6 +16,7 @@ package proxy
import
(
"fmt"
"net"
"strings"
"github.com/fatedier/frp/models/config"
...
...
@@ -27,21 +28,24 @@ import (
type
TcpMuxProxy
struct
{
*
BaseProxy
cfg
*
config
.
TcpMuxProxyConf
realPort
int
}
func
(
pxy
*
TcpMuxProxy
)
httpConnectListen
(
domain
string
,
addrs
[]
string
)
([]
string
,
error
)
{
routeConfig
:=
&
vhost
.
VhostRouteConfig
{
Domain
:
domain
,
func
(
pxy
*
TcpMuxProxy
)
httpConnectListen
(
domain
string
,
addrs
[]
string
)
(
_
[]
string
,
err
error
)
{
var
l
net
.
Listener
if
pxy
.
cfg
.
Group
!=
""
{
l
,
err
=
pxy
.
rc
.
TcpMuxGroupCtl
.
Listen
(
pxy
.
cfg
.
Multiplexer
,
pxy
.
cfg
.
Group
,
pxy
.
cfg
.
GroupKey
,
domain
,
pxy
.
ctx
)
}
else
{
routeConfig
:=
&
vhost
.
VhostRouteConfig
{
Domain
:
domain
,
}
l
,
err
=
pxy
.
rc
.
TcpMuxHttpConnectMuxer
.
Listen
(
pxy
.
ctx
,
routeConfig
)
}
l
,
err
:=
pxy
.
rc
.
TcpMuxHttpConnectMuxer
.
Listen
(
pxy
.
ctx
,
routeConfig
)
if
err
!=
nil
{
return
nil
,
err
}
pxy
.
xl
.
Info
(
"tcpmux httpconnect multiplexer listens for host [%s]"
,
routeConfig
.
D
omain
)
pxy
.
xl
.
Info
(
"tcpmux httpconnect multiplexer listens for host [%s]"
,
d
omain
)
pxy
.
listeners
=
append
(
pxy
.
listeners
,
l
)
return
append
(
addrs
,
util
.
CanonicalAddr
(
routeConfig
.
D
omain
,
pxy
.
serverCfg
.
TcpMuxHttpConnectPort
)),
nil
return
append
(
addrs
,
util
.
CanonicalAddr
(
d
omain
,
pxy
.
serverCfg
.
TcpMuxHttpConnectPort
)),
nil
}
func
(
pxy
*
TcpMuxProxy
)
httpConnectRun
()
(
remoteAddr
string
,
err
error
)
{
...
...
@@ -89,7 +93,4 @@ func (pxy *TcpMuxProxy) GetConf() config.ProxyConf {
func
(
pxy
*
TcpMuxProxy
)
Close
()
{
pxy
.
BaseProxy
.
Close
()
if
pxy
.
cfg
.
Group
==
""
{
pxy
.
rc
.
TcpPortManager
.
Release
(
pxy
.
realPort
)
}
}
server/service.go
浏览文件 @
6d78af61
...
...
@@ -114,6 +114,23 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
cfg
:
cfg
,
}
// Create tcpmux httpconnect multiplexer.
if
cfg
.
TcpMuxHttpConnectPort
>
0
{
var
l
net
.
Listener
l
,
err
=
net
.
Listen
(
"tcp"
,
fmt
.
Sprintf
(
"%s:%d"
,
cfg
.
ProxyBindAddr
,
cfg
.
TcpMuxHttpConnectPort
))
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Create server listener error, %v"
,
err
)
return
}
svr
.
rc
.
TcpMuxHttpConnectMuxer
,
err
=
tcpmux
.
NewHttpConnectTcpMuxer
(
l
,
vhostReadWriteTimeout
)
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Create vhost tcpMuxer error, %v"
,
err
)
return
}
log
.
Info
(
"tcpmux httpconnect multiplexer listen on %s:%d"
,
cfg
.
ProxyBindAddr
,
cfg
.
TcpMuxHttpConnectPort
)
}
// Init all plugins
for
name
,
options
:=
range
cfg
.
HTTPPlugins
{
svr
.
pluginManager
.
Register
(
plugin
.
NewHTTPPluginOptions
(
options
))
...
...
@@ -127,6 +144,9 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
// Init HTTP group controller
svr
.
rc
.
HTTPGroupCtl
=
group
.
NewHTTPGroupController
(
svr
.
httpVhostRouter
)
// Init TCP mux group controller
svr
.
rc
.
TcpMuxGroupCtl
=
group
.
NewTcpMuxGroupCtl
(
svr
.
rc
.
TcpMuxHttpConnectMuxer
)
// Init 404 not found page
vhost
.
NotFoundPagePath
=
cfg
.
Custom404Page
...
...
@@ -221,23 +241,6 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
log
.
Info
(
"https service listen on %s:%d"
,
cfg
.
ProxyBindAddr
,
cfg
.
VhostHttpsPort
)
}
// Create tcpmux httpconnect multiplexer.
if
cfg
.
TcpMuxHttpConnectPort
>
0
{
var
l
net
.
Listener
l
,
err
=
net
.
Listen
(
"tcp"
,
fmt
.
Sprintf
(
"%s:%d"
,
cfg
.
ProxyBindAddr
,
cfg
.
TcpMuxHttpConnectPort
))
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Create server listener error, %v"
,
err
)
return
}
svr
.
rc
.
TcpMuxHttpConnectMuxer
,
err
=
tcpmux
.
NewHttpConnectTcpMuxer
(
l
,
vhostReadWriteTimeout
)
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Create vhost tcpMuxer error, %v"
,
err
)
return
}
log
.
Info
(
"tcpmux httpconnect multiplexer listen on %s:%d"
,
cfg
.
ProxyBindAddr
,
cfg
.
TcpMuxHttpConnectPort
)
}
// frp tls listener
svr
.
tlsListener
=
svr
.
muxer
.
Listen
(
1
,
1
,
func
(
data
[]
byte
)
bool
{
return
int
(
data
[
0
])
==
frpNet
.
FRP_TLS_HEAD_BYTE
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录