Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
企猫商务
frp
提交
47971369
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 搜索 >>
未验证
提交
47971369
编写于
4月 22, 2020
作者:
T
Tank
提交者:
GitHub
4月 22, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: support sudp proxy (#1730)
上级
6d78af61
变更
15
隐藏空白更改
内联
并排
Showing
15 changed file
with
669 addition
and
1 deletion
+669
-1
client/admin_api.go
client/admin_api.go
+10
-0
client/proxy/proxy.go
client/proxy/proxy.go
+151
-0
client/visitor.go
client/visitor.go
+209
-0
cmd/frpc/sub/sudp.go
cmd/frpc/sub/sudp.go
+113
-0
models/config/proxy.go
models/config/proxy.go
+67
-0
models/config/visitor.go
models/config/visitor.go
+31
-0
models/consts/consts.go
models/consts/consts.go
+1
-0
models/proto/udp/udp.go
models/proto/udp/udp.go
+1
-1
server/proxy/proxy.go
server/proxy/proxy.go
+5
-0
server/proxy/sudp.go
server/proxy/sudp.go
+48
-0
tests/ci/auto_test_frpc.ini
tests/ci/auto_test_frpc.ini
+6
-0
tests/ci/auto_test_frpc_visitor.ini
tests/ci/auto_test_frpc_visitor.ini
+9
-0
tests/ci/normal_test.go
tests/ci/normal_test.go
+10
-0
tests/consts/consts.go
tests/consts/consts.go
+3
-0
tests/util/util.go
tests/util/util.go
+5
-0
未找到文件。
client/admin_api.go
浏览文件 @
47971369
...
@@ -88,6 +88,7 @@ type StatusResp struct {
...
@@ -88,6 +88,7 @@ type StatusResp struct {
Https
[]
ProxyStatusResp
`json:"https"`
Https
[]
ProxyStatusResp
`json:"https"`
Stcp
[]
ProxyStatusResp
`json:"stcp"`
Stcp
[]
ProxyStatusResp
`json:"stcp"`
Xtcp
[]
ProxyStatusResp
`json:"xtcp"`
Xtcp
[]
ProxyStatusResp
`json:"xtcp"`
Sudp
[]
ProxyStatusResp
`json:"sudp"`
}
}
type
ProxyStatusResp
struct
{
type
ProxyStatusResp
struct
{
...
@@ -155,6 +156,11 @@ func NewProxyStatusResp(status *proxy.ProxyStatus, serverAddr string) ProxyStatu
...
@@ -155,6 +156,11 @@ func NewProxyStatusResp(status *proxy.ProxyStatus, serverAddr string) ProxyStatu
psr
.
LocalAddr
=
fmt
.
Sprintf
(
"%s:%d"
,
cfg
.
LocalIp
,
cfg
.
LocalPort
)
psr
.
LocalAddr
=
fmt
.
Sprintf
(
"%s:%d"
,
cfg
.
LocalIp
,
cfg
.
LocalPort
)
}
}
psr
.
Plugin
=
cfg
.
Plugin
psr
.
Plugin
=
cfg
.
Plugin
case
*
config
.
SudpProxyConf
:
if
cfg
.
LocalPort
!=
0
{
psr
.
LocalAddr
=
fmt
.
Sprintf
(
"%s:%d"
,
cfg
.
LocalIp
,
cfg
.
LocalPort
)
}
psr
.
Plugin
=
cfg
.
Plugin
}
}
return
psr
return
psr
}
}
...
@@ -171,6 +177,7 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
...
@@ -171,6 +177,7 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
res
.
Https
=
make
([]
ProxyStatusResp
,
0
)
res
.
Https
=
make
([]
ProxyStatusResp
,
0
)
res
.
Stcp
=
make
([]
ProxyStatusResp
,
0
)
res
.
Stcp
=
make
([]
ProxyStatusResp
,
0
)
res
.
Xtcp
=
make
([]
ProxyStatusResp
,
0
)
res
.
Xtcp
=
make
([]
ProxyStatusResp
,
0
)
res
.
Sudp
=
make
([]
ProxyStatusResp
,
0
)
log
.
Info
(
"Http request [/api/status]"
)
log
.
Info
(
"Http request [/api/status]"
)
defer
func
()
{
defer
func
()
{
...
@@ -194,6 +201,8 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
...
@@ -194,6 +201,8 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
res
.
Stcp
=
append
(
res
.
Stcp
,
NewProxyStatusResp
(
status
,
svr
.
cfg
.
ServerAddr
))
res
.
Stcp
=
append
(
res
.
Stcp
,
NewProxyStatusResp
(
status
,
svr
.
cfg
.
ServerAddr
))
case
"xtcp"
:
case
"xtcp"
:
res
.
Xtcp
=
append
(
res
.
Xtcp
,
NewProxyStatusResp
(
status
,
svr
.
cfg
.
ServerAddr
))
res
.
Xtcp
=
append
(
res
.
Xtcp
,
NewProxyStatusResp
(
status
,
svr
.
cfg
.
ServerAddr
))
case
"sudp"
:
res
.
Sudp
=
append
(
res
.
Sudp
,
NewProxyStatusResp
(
status
,
svr
.
cfg
.
ServerAddr
))
}
}
}
}
sort
.
Sort
(
ByProxyStatusResp
(
res
.
Tcp
))
sort
.
Sort
(
ByProxyStatusResp
(
res
.
Tcp
))
...
@@ -202,6 +211,7 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
...
@@ -202,6 +211,7 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
sort
.
Sort
(
ByProxyStatusResp
(
res
.
Https
))
sort
.
Sort
(
ByProxyStatusResp
(
res
.
Https
))
sort
.
Sort
(
ByProxyStatusResp
(
res
.
Stcp
))
sort
.
Sort
(
ByProxyStatusResp
(
res
.
Stcp
))
sort
.
Sort
(
ByProxyStatusResp
(
res
.
Xtcp
))
sort
.
Sort
(
ByProxyStatusResp
(
res
.
Xtcp
))
sort
.
Sort
(
ByProxyStatusResp
(
res
.
Sudp
))
return
return
}
}
...
...
client/proxy/proxy.go
浏览文件 @
47971369
...
@@ -102,6 +102,12 @@ func NewProxy(ctx context.Context, pxyConf config.ProxyConf, clientCfg config.Cl
...
@@ -102,6 +102,12 @@ func NewProxy(ctx context.Context, pxyConf config.ProxyConf, clientCfg config.Cl
BaseProxy
:
&
baseProxy
,
BaseProxy
:
&
baseProxy
,
cfg
:
cfg
,
cfg
:
cfg
,
}
}
case
*
config
.
SudpProxyConf
:
pxy
=
&
SudpProxy
{
BaseProxy
:
&
baseProxy
,
cfg
:
cfg
,
closeCh
:
make
(
chan
struct
{}),
}
}
}
return
return
}
}
...
@@ -540,6 +546,151 @@ func (pxy *UdpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
...
@@ -540,6 +546,151 @@ func (pxy *UdpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
udp
.
Forwarder
(
pxy
.
localAddr
,
pxy
.
readCh
,
pxy
.
sendCh
)
udp
.
Forwarder
(
pxy
.
localAddr
,
pxy
.
readCh
,
pxy
.
sendCh
)
}
}
type
SudpProxy
struct
{
*
BaseProxy
cfg
*
config
.
SudpProxyConf
localAddr
*
net
.
UDPAddr
closeCh
chan
struct
{}
}
func
(
pxy
*
SudpProxy
)
Run
()
(
err
error
)
{
pxy
.
localAddr
,
err
=
net
.
ResolveUDPAddr
(
"udp"
,
fmt
.
Sprintf
(
"%s:%d"
,
pxy
.
cfg
.
LocalIp
,
pxy
.
cfg
.
LocalPort
))
if
err
!=
nil
{
return
}
return
}
func
(
pxy
*
SudpProxy
)
Close
()
{
pxy
.
mu
.
Lock
()
defer
pxy
.
mu
.
Unlock
()
select
{
case
<-
pxy
.
closeCh
:
return
default
:
close
(
pxy
.
closeCh
)
}
}
func
(
pxy
*
SudpProxy
)
InWorkConn
(
conn
net
.
Conn
,
m
*
msg
.
StartWorkConn
)
{
xl
:=
pxy
.
xl
xl
.
Info
(
"incoming a new work connection for sudp proxy, %s"
,
conn
.
RemoteAddr
()
.
String
())
if
pxy
.
limiter
!=
nil
{
rwc
:=
frpIo
.
WrapReadWriteCloser
(
limit
.
NewReader
(
conn
,
pxy
.
limiter
),
limit
.
NewWriter
(
conn
,
pxy
.
limiter
),
func
()
error
{
return
conn
.
Close
()
})
conn
=
frpNet
.
WrapReadWriteCloserToConn
(
rwc
,
conn
)
}
workConn
:=
conn
readCh
:=
make
(
chan
*
msg
.
UdpPacket
,
1024
)
sendCh
:=
make
(
chan
msg
.
Message
,
1024
)
isClose
:=
false
mu
:=
&
sync
.
Mutex
{}
closeFn
:=
func
()
{
mu
.
Lock
()
defer
mu
.
Unlock
()
if
isClose
{
return
}
isClose
=
true
if
workConn
!=
nil
{
workConn
.
Close
()
}
close
(
readCh
)
close
(
sendCh
)
}
// udp service <- frpc <- frps <- frpc visitor <- user
workConnReaderFn
:=
func
(
conn
net
.
Conn
,
readCh
chan
*
msg
.
UdpPacket
)
{
defer
closeFn
()
for
{
// first to check sudp proxy is closed or not
select
{
case
<-
pxy
.
closeCh
:
xl
.
Trace
(
"frpc sudp proxy is closed"
)
return
default
:
}
var
udpMsg
msg
.
UdpPacket
if
errRet
:=
msg
.
ReadMsgInto
(
conn
,
&
udpMsg
);
errRet
!=
nil
{
xl
.
Warn
(
"read from workConn for sudp error: %v"
,
errRet
)
return
}
if
errRet
:=
errors
.
PanicToError
(
func
()
{
readCh
<-
&
udpMsg
});
errRet
!=
nil
{
xl
.
Warn
(
"reader goroutine for sudp work connection closed: %v"
,
errRet
)
return
}
}
}
// udp service -> frpc -> frps -> frpc visitor -> user
workConnSenderFn
:=
func
(
conn
net
.
Conn
,
sendCh
chan
msg
.
Message
)
{
defer
func
()
{
closeFn
()
xl
.
Info
(
"writer goroutine for sudp work connection closed"
)
}()
var
errRet
error
for
rawMsg
:=
range
sendCh
{
switch
m
:=
rawMsg
.
(
type
)
{
case
*
msg
.
UdpPacket
:
xl
.
Trace
(
"frpc send udp package to frpc visitor, [udp local: %v, remote: %v], [tcp work conn local: %v, remote: %v]"
,
m
.
LocalAddr
.
String
(),
m
.
RemoteAddr
.
String
(),
conn
.
LocalAddr
()
.
String
(),
conn
.
RemoteAddr
()
.
String
())
case
*
msg
.
Ping
:
xl
.
Trace
(
"frpc send ping message to frpc visitor"
)
}
if
errRet
=
msg
.
WriteMsg
(
conn
,
rawMsg
);
errRet
!=
nil
{
xl
.
Error
(
"sudp work write error: %v"
,
errRet
)
return
}
}
}
heartbeatFn
:=
func
(
conn
net
.
Conn
,
sendCh
chan
msg
.
Message
)
{
ticker
:=
time
.
NewTicker
(
30
*
time
.
Second
)
defer
func
()
{
ticker
.
Stop
()
closeFn
()
}()
var
errRet
error
for
{
select
{
case
<-
ticker
.
C
:
if
errRet
=
errors
.
PanicToError
(
func
()
{
sendCh
<-
&
msg
.
Ping
{}
});
errRet
!=
nil
{
xl
.
Warn
(
"heartbeat goroutine for sudp work connection closed"
)
return
}
case
<-
pxy
.
closeCh
:
xl
.
Trace
(
"frpc sudp proxy is closed"
)
return
}
}
}
go
workConnSenderFn
(
workConn
,
sendCh
)
go
workConnReaderFn
(
workConn
,
readCh
)
go
heartbeatFn
(
workConn
,
sendCh
)
udp
.
Forwarder
(
pxy
.
localAddr
,
readCh
,
sendCh
)
}
// Common handler for tcp work connections.
// Common handler for tcp work connections.
func
HandleTcpWorkConnection
(
ctx
context
.
Context
,
localInfo
*
config
.
LocalSvrConf
,
proxyPlugin
plugin
.
Plugin
,
func
HandleTcpWorkConnection
(
ctx
context
.
Context
,
localInfo
*
config
.
LocalSvrConf
,
proxyPlugin
plugin
.
Plugin
,
baseInfo
*
config
.
BaseProxyConf
,
limiter
*
rate
.
Limiter
,
workConn
net
.
Conn
,
encKey
[]
byte
,
m
*
msg
.
StartWorkConn
)
{
baseInfo
*
config
.
BaseProxyConf
,
limiter
*
rate
.
Limiter
,
workConn
net
.
Conn
,
encKey
[]
byte
,
m
*
msg
.
StartWorkConn
)
{
...
...
client/visitor.go
浏览文件 @
47971369
...
@@ -26,10 +26,12 @@ import (
...
@@ -26,10 +26,12 @@ import (
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/msg"
"github.com/fatedier/frp/models/msg"
"github.com/fatedier/frp/models/proto/udp"
frpNet
"github.com/fatedier/frp/utils/net"
frpNet
"github.com/fatedier/frp/utils/net"
"github.com/fatedier/frp/utils/util"
"github.com/fatedier/frp/utils/util"
"github.com/fatedier/frp/utils/xlog"
"github.com/fatedier/frp/utils/xlog"
"github.com/fatedier/golib/errors"
frpIo
"github.com/fatedier/golib/io"
frpIo
"github.com/fatedier/golib/io"
"github.com/fatedier/golib/pool"
"github.com/fatedier/golib/pool"
fmux
"github.com/hashicorp/yamux"
fmux
"github.com/hashicorp/yamux"
...
@@ -58,6 +60,12 @@ func NewVisitor(ctx context.Context, ctl *Control, cfg config.VisitorConf) (visi
...
@@ -58,6 +60,12 @@ func NewVisitor(ctx context.Context, ctl *Control, cfg config.VisitorConf) (visi
BaseVisitor
:
&
baseVisitor
,
BaseVisitor
:
&
baseVisitor
,
cfg
:
cfg
,
cfg
:
cfg
,
}
}
case
*
config
.
SudpVisitorConf
:
visitor
=
&
SudpVisitor
{
BaseVisitor
:
&
baseVisitor
,
cfg
:
cfg
,
checkCloseCh
:
make
(
chan
struct
{}),
}
}
}
return
return
}
}
...
@@ -328,3 +336,204 @@ func (sv *XtcpVisitor) handleConn(userConn net.Conn) {
...
@@ -328,3 +336,204 @@ func (sv *XtcpVisitor) handleConn(userConn net.Conn) {
frpIo
.
Join
(
userConn
,
muxConnRWCloser
)
frpIo
.
Join
(
userConn
,
muxConnRWCloser
)
xl
.
Debug
(
"join connections closed"
)
xl
.
Debug
(
"join connections closed"
)
}
}
type
SudpVisitor
struct
{
*
BaseVisitor
checkCloseCh
chan
struct
{}
// udpConn is the listener of udp packet
udpConn
*
net
.
UDPConn
readCh
chan
*
msg
.
UdpPacket
sendCh
chan
*
msg
.
UdpPacket
cfg
*
config
.
SudpVisitorConf
}
// SUDP Run start listen a udp port
func
(
sv
*
SudpVisitor
)
Run
()
(
err
error
)
{
xl
:=
xlog
.
FromContextSafe
(
sv
.
ctx
)
addr
,
err
:=
net
.
ResolveUDPAddr
(
"udp"
,
fmt
.
Sprintf
(
"%s:%d"
,
sv
.
cfg
.
BindAddr
,
sv
.
cfg
.
BindPort
))
if
err
!=
nil
{
return
fmt
.
Errorf
(
"sudp ResolveUDPAddr error: %v"
,
err
)
}
sv
.
udpConn
,
err
=
net
.
ListenUDP
(
"udp"
,
addr
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"listen udp port %s error: %v"
,
addr
.
String
(),
err
)
}
sv
.
sendCh
=
make
(
chan
*
msg
.
UdpPacket
,
1024
)
sv
.
readCh
=
make
(
chan
*
msg
.
UdpPacket
,
1024
)
xl
.
Info
(
"sudp start to work"
)
go
sv
.
dispatcher
()
go
udp
.
ForwardUserConn
(
sv
.
udpConn
,
sv
.
readCh
,
sv
.
sendCh
)
return
}
func
(
sv
*
SudpVisitor
)
dispatcher
()
{
xl
:=
xlog
.
FromContextSafe
(
sv
.
ctx
)
for
{
// loop for get frpc to frps tcp conn
// setup worker
// wait worker to finished
// retry or exit
visitorConn
,
err
:=
sv
.
getNewVisitorConn
()
if
err
!=
nil
{
// check if proxy is closed
// if checkCloseCh is close, we will return, other case we will continue to reconnect
select
{
case
<-
sv
.
checkCloseCh
:
xl
.
Info
(
"frpc sudp visitor proxy is closed"
)
return
default
:
}
time
.
Sleep
(
3
*
time
.
Second
)
xl
.
Warn
(
"newVisitorConn to frps error: %v, try to reconnect"
,
err
)
continue
}
sv
.
worker
(
visitorConn
)
select
{
case
<-
sv
.
checkCloseCh
:
return
default
:
}
}
}
func
(
sv
*
SudpVisitor
)
worker
(
workConn
net
.
Conn
)
{
xl
:=
xlog
.
FromContextSafe
(
sv
.
ctx
)
xl
.
Debug
(
"starting sudp proxy worker"
)
wg
:=
&
sync
.
WaitGroup
{}
wg
.
Add
(
2
)
closeCh
:=
make
(
chan
struct
{})
// udp service -> frpc -> frps -> frpc visitor -> user
workConnReaderFn
:=
func
(
conn
net
.
Conn
)
{
defer
func
()
{
conn
.
Close
()
close
(
closeCh
)
wg
.
Done
()
}()
for
{
var
(
rawMsg
msg
.
Message
errRet
error
)
// frpc will send heartbeat in workConn to frpc visitor for keeping alive
conn
.
SetReadDeadline
(
time
.
Now
()
.
Add
(
60
*
time
.
Second
))
if
rawMsg
,
errRet
=
msg
.
ReadMsg
(
conn
);
errRet
!=
nil
{
xl
.
Warn
(
"read from workconn for user udp conn error: %v"
,
errRet
)
return
}
conn
.
SetReadDeadline
(
time
.
Time
{})
switch
m
:=
rawMsg
.
(
type
)
{
case
*
msg
.
Ping
:
xl
.
Debug
(
"frpc visitor get ping message from frpc"
)
continue
case
*
msg
.
UdpPacket
:
if
errRet
:=
errors
.
PanicToError
(
func
()
{
sv
.
readCh
<-
m
xl
.
Trace
(
"frpc visitor get udp packet from frpc"
)
});
errRet
!=
nil
{
xl
.
Info
(
"reader goroutine for udp work connection closed"
)
return
}
}
}
}
// udp service <- frpc <- frps <- frpc visitor <- user
workConnSenderFn
:=
func
(
conn
net
.
Conn
)
{
defer
func
()
{
conn
.
Close
()
wg
.
Done
()
}()
var
errRet
error
for
{
select
{
case
udpMsg
,
ok
:=
<-
sv
.
sendCh
:
if
!
ok
{
xl
.
Info
(
"sender goroutine for udp work connection closed"
)
return
}
if
errRet
=
msg
.
WriteMsg
(
conn
,
udpMsg
);
errRet
!=
nil
{
xl
.
Warn
(
"sender goroutine for udp work connection closed: %v"
,
errRet
)
return
}
case
<-
closeCh
:
return
}
}
}
go
workConnReaderFn
(
workConn
)
go
workConnSenderFn
(
workConn
)
wg
.
Wait
()
xl
.
Info
(
"sudp worker is closed"
)
}
func
(
sv
*
SudpVisitor
)
getNewVisitorConn
()
(
visitorConn
net
.
Conn
,
err
error
)
{
visitorConn
,
err
=
sv
.
ctl
.
connectServer
()
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"frpc connect frps error: %v"
,
err
)
}
now
:=
time
.
Now
()
.
Unix
()
newVisitorConnMsg
:=
&
msg
.
NewVisitorConn
{
ProxyName
:
sv
.
cfg
.
ServerName
,
SignKey
:
util
.
GetAuthKey
(
sv
.
cfg
.
Sk
,
now
),
Timestamp
:
now
,
UseEncryption
:
sv
.
cfg
.
UseEncryption
,
UseCompression
:
sv
.
cfg
.
UseCompression
,
}
err
=
msg
.
WriteMsg
(
visitorConn
,
newVisitorConnMsg
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"frpc send newVisitorConnMsg to frps error: %v"
,
err
)
}
var
newVisitorConnRespMsg
msg
.
NewVisitorConnResp
visitorConn
.
SetReadDeadline
(
time
.
Now
()
.
Add
(
10
*
time
.
Second
))
err
=
msg
.
ReadMsgInto
(
visitorConn
,
&
newVisitorConnRespMsg
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"frpc read newVisitorConnRespMsg error: %v"
,
err
)
}
visitorConn
.
SetReadDeadline
(
time
.
Time
{})
if
newVisitorConnRespMsg
.
Error
!=
""
{
return
nil
,
fmt
.
Errorf
(
"start new visitor connection error: %s"
,
newVisitorConnRespMsg
.
Error
)
}
return
}
func
(
sv
*
SudpVisitor
)
Close
()
{
sv
.
mu
.
Lock
()
defer
sv
.
mu
.
Unlock
()
select
{
case
<-
sv
.
checkCloseCh
:
return
default
:
close
(
sv
.
checkCloseCh
)
}
if
sv
.
udpConn
!=
nil
{
sv
.
udpConn
.
Close
()
}
close
(
sv
.
readCh
)
close
(
sv
.
sendCh
)
}
cmd/frpc/sub/sudp.go
0 → 100644
浏览文件 @
47971369
// Copyright 2018 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
sub
import
(
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/consts"
)
func
init
()
{
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
serverAddr
,
"server_addr"
,
"s"
,
"127.0.0.1:7000"
,
"frp server's address"
)
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
user
,
"user"
,
"u"
,
""
,
"user"
)
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
protocol
,
"protocol"
,
"p"
,
"tcp"
,
"tcp or kcp or websocket"
)
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
token
,
"token"
,
"t"
,
""
,
"auth token"
)
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
logLevel
,
"log_level"
,
""
,
"info"
,
"log level"
)
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
logFile
,
"log_file"
,
""
,
"console"
,
"console or file path"
)
sudpCmd
.
PersistentFlags
()
.
IntVarP
(
&
logMaxDays
,
"log_max_days"
,
""
,
3
,
"log file reversed days"
)
sudpCmd
.
PersistentFlags
()
.
BoolVarP
(
&
disableLogColor
,
"disable_log_color"
,
""
,
false
,
"disable log color in console"
)
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
proxyName
,
"proxy_name"
,
"n"
,
""
,
"proxy name"
)
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
role
,
"role"
,
""
,
"server"
,
"role"
)
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
sk
,
"sk"
,
""
,
""
,
"secret key"
)
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
serverName
,
"server_name"
,
""
,
""
,
"server name"
)
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
localIp
,
"local_ip"
,
"i"
,
"127.0.0.1"
,
"local ip"
)
sudpCmd
.
PersistentFlags
()
.
IntVarP
(
&
localPort
,
"local_port"
,
"l"
,
0
,
"local port"
)
sudpCmd
.
PersistentFlags
()
.
StringVarP
(
&
bindAddr
,
"bind_addr"
,
""
,
""
,
"bind addr"
)
sudpCmd
.
PersistentFlags
()
.
IntVarP
(
&
bindPort
,
"bind_port"
,
""
,
0
,
"bind port"
)
sudpCmd
.
PersistentFlags
()
.
BoolVarP
(
&
useEncryption
,
"ue"
,
""
,
false
,
"use encryption"
)
sudpCmd
.
PersistentFlags
()
.
BoolVarP
(
&
useCompression
,
"uc"
,
""
,
false
,
"use compression"
)
rootCmd
.
AddCommand
(
sudpCmd
)
}
var
sudpCmd
=
&
cobra
.
Command
{
Use
:
"sudp"
,
Short
:
"Run frpc with a single sudp proxy"
,
RunE
:
func
(
cmd
*
cobra
.
Command
,
args
[]
string
)
error
{
clientCfg
,
err
:=
parseClientCommonCfg
(
CfgFileTypeCmd
,
""
)
if
err
!=
nil
{
fmt
.
Println
(
err
)
os
.
Exit
(
1
)
}
proxyConfs
:=
make
(
map
[
string
]
config
.
ProxyConf
)
visitorConfs
:=
make
(
map
[
string
]
config
.
VisitorConf
)
var
prefix
string
if
user
!=
""
{
prefix
=
user
+
"."
}
if
role
==
"server"
{
cfg
:=
&
config
.
SudpProxyConf
{}
cfg
.
ProxyName
=
prefix
+
proxyName
cfg
.
ProxyType
=
consts
.
SudpProxy
cfg
.
UseEncryption
=
useEncryption
cfg
.
UseCompression
=
useCompression
cfg
.
Role
=
role
cfg
.
Sk
=
sk
cfg
.
LocalIp
=
localIp
cfg
.
LocalPort
=
localPort
err
=
cfg
.
CheckForCli
()
if
err
!=
nil
{
fmt
.
Println
(
err
)
os
.
Exit
(
1
)
}
proxyConfs
[
cfg
.
ProxyName
]
=
cfg
}
else
if
role
==
"visitor"
{
cfg
:=
&
config
.
SudpVisitorConf
{}
cfg
.
ProxyName
=
prefix
+
proxyName
cfg
.
ProxyType
=
consts
.
SudpProxy
cfg
.
UseEncryption
=
useEncryption
cfg
.
UseCompression
=
useCompression
cfg
.
Role
=
role
cfg
.
Sk
=
sk
cfg
.
ServerName
=
serverName
cfg
.
BindAddr
=
bindAddr
cfg
.
BindPort
=
bindPort
err
=
cfg
.
Check
()
if
err
!=
nil
{
fmt
.
Println
(
err
)
os
.
Exit
(
1
)
}
visitorConfs
[
cfg
.
ProxyName
]
=
cfg
}
else
{
fmt
.
Println
(
"invalid role"
)
os
.
Exit
(
1
)
}
err
=
startService
(
clientCfg
,
proxyConfs
,
visitorConfs
,
""
)
if
err
!=
nil
{
os
.
Exit
(
1
)
}
return
nil
},
}
models/config/proxy.go
浏览文件 @
47971369
...
@@ -40,6 +40,7 @@ func init() {
...
@@ -40,6 +40,7 @@ func init() {
proxyConfTypeMap
[
consts
.
HttpsProxy
]
=
reflect
.
TypeOf
(
HttpsProxyConf
{})
proxyConfTypeMap
[
consts
.
HttpsProxy
]
=
reflect
.
TypeOf
(
HttpsProxyConf
{})
proxyConfTypeMap
[
consts
.
StcpProxy
]
=
reflect
.
TypeOf
(
StcpProxyConf
{})
proxyConfTypeMap
[
consts
.
StcpProxy
]
=
reflect
.
TypeOf
(
StcpProxyConf
{})
proxyConfTypeMap
[
consts
.
XtcpProxy
]
=
reflect
.
TypeOf
(
XtcpProxyConf
{})
proxyConfTypeMap
[
consts
.
XtcpProxy
]
=
reflect
.
TypeOf
(
XtcpProxyConf
{})
proxyConfTypeMap
[
consts
.
SudpProxy
]
=
reflect
.
TypeOf
(
SudpProxyConf
{})
}
}
// NewConfByType creates a empty ProxyConf object by proxyType.
// NewConfByType creates a empty ProxyConf object by proxyType.
...
@@ -875,6 +876,72 @@ func (cfg *HttpsProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
...
@@ -875,6 +876,72 @@ func (cfg *HttpsProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
return
return
}
}
// SUDP
type
SudpProxyConf
struct
{
BaseProxyConf
Role
string
`json:"role"`
Sk
string
`json:"sk"`
}
func
(
cfg
*
SudpProxyConf
)
Compare
(
cmp
ProxyConf
)
bool
{
cmpConf
,
ok
:=
cmp
.
(
*
SudpProxyConf
)
if
!
ok
{
return
false
}
if
!
cfg
.
BaseProxyConf
.
compare
(
&
cmpConf
.
BaseProxyConf
)
||
cfg
.
Role
!=
cmpConf
.
Role
||
cfg
.
Sk
!=
cmpConf
.
Sk
{
return
false
}
return
true
}
func
(
cfg
*
SudpProxyConf
)
UnmarshalFromIni
(
prefix
string
,
name
string
,
section
ini
.
Section
)
(
err
error
)
{
if
err
=
cfg
.
BaseProxyConf
.
UnmarshalFromIni
(
prefix
,
name
,
section
);
err
!=
nil
{
return
}
cfg
.
Role
=
section
[
"role"
]
if
cfg
.
Role
!=
"server"
{
return
fmt
.
Errorf
(
"Parse conf error: proxy [%s] incorrect role [%s]"
,
name
,
cfg
.
Role
)
}
cfg
.
Sk
=
section
[
"sk"
]
if
err
=
cfg
.
LocalSvrConf
.
UnmarshalFromIni
(
prefix
,
name
,
section
);
err
!=
nil
{
return
}
return
}
func
(
cfg
*
SudpProxyConf
)
MarshalToMsg
(
pMsg
*
msg
.
NewProxy
)
{
cfg
.
BaseProxyConf
.
MarshalToMsg
(
pMsg
)
pMsg
.
Sk
=
cfg
.
Sk
}
func
(
cfg
*
SudpProxyConf
)
CheckForCli
()
(
err
error
)
{
if
err
=
cfg
.
BaseProxyConf
.
checkForCli
();
err
!=
nil
{
return
}
if
cfg
.
Role
!=
"server"
{
err
=
fmt
.
Errorf
(
"role should be 'server'"
)
return
}
return
}
func
(
cfg
*
SudpProxyConf
)
CheckForSvr
(
serverCfg
ServerCommonConf
)
(
err
error
)
{
return
}
// Only for role server.
func
(
cfg
*
SudpProxyConf
)
UnmarshalFromMsg
(
pMsg
*
msg
.
NewProxy
)
{
cfg
.
BaseProxyConf
.
UnmarshalFromMsg
(
pMsg
)
cfg
.
Sk
=
pMsg
.
Sk
}
// STCP
// STCP
type
StcpProxyConf
struct
{
type
StcpProxyConf
struct
{
BaseProxyConf
BaseProxyConf
...
...
models/config/visitor.go
浏览文件 @
47971369
...
@@ -32,6 +32,7 @@ func init() {
...
@@ -32,6 +32,7 @@ func init() {
visitorConfTypeMap
=
make
(
map
[
string
]
reflect
.
Type
)
visitorConfTypeMap
=
make
(
map
[
string
]
reflect
.
Type
)
visitorConfTypeMap
[
consts
.
StcpProxy
]
=
reflect
.
TypeOf
(
StcpVisitorConf
{})
visitorConfTypeMap
[
consts
.
StcpProxy
]
=
reflect
.
TypeOf
(
StcpVisitorConf
{})
visitorConfTypeMap
[
consts
.
XtcpProxy
]
=
reflect
.
TypeOf
(
XtcpVisitorConf
{})
visitorConfTypeMap
[
consts
.
XtcpProxy
]
=
reflect
.
TypeOf
(
XtcpVisitorConf
{})
visitorConfTypeMap
[
consts
.
SudpProxy
]
=
reflect
.
TypeOf
(
SudpVisitorConf
{})
}
}
type
VisitorConf
interface
{
type
VisitorConf
interface
{
...
@@ -152,6 +153,36 @@ func (cfg *BaseVisitorConf) UnmarshalFromIni(prefix string, name string, section
...
@@ -152,6 +153,36 @@ func (cfg *BaseVisitorConf) UnmarshalFromIni(prefix string, name string, section
return
nil
return
nil
}
}
type
SudpVisitorConf
struct
{
BaseVisitorConf
}
func
(
cfg
*
SudpVisitorConf
)
Compare
(
cmp
VisitorConf
)
bool
{
cmpConf
,
ok
:=
cmp
.
(
*
SudpVisitorConf
)
if
!
ok
{
return
false
}
if
!
cfg
.
BaseVisitorConf
.
compare
(
&
cmpConf
.
BaseVisitorConf
)
{
return
false
}
return
true
}
func
(
cfg
*
SudpVisitorConf
)
UnmarshalFromIni
(
prefix
string
,
name
string
,
section
ini
.
Section
)
(
err
error
)
{
if
err
=
cfg
.
BaseVisitorConf
.
UnmarshalFromIni
(
prefix
,
name
,
section
);
err
!=
nil
{
return
}
return
}
func
(
cfg
*
SudpVisitorConf
)
Check
()
(
err
error
)
{
if
err
=
cfg
.
BaseVisitorConf
.
check
();
err
!=
nil
{
return
}
return
}
type
StcpVisitorConf
struct
{
type
StcpVisitorConf
struct
{
BaseVisitorConf
BaseVisitorConf
}
}
...
...
models/consts/consts.go
浏览文件 @
47971369
...
@@ -30,6 +30,7 @@ var (
...
@@ -30,6 +30,7 @@ var (
HttpsProxy
string
=
"https"
HttpsProxy
string
=
"https"
StcpProxy
string
=
"stcp"
StcpProxy
string
=
"stcp"
XtcpProxy
string
=
"xtcp"
XtcpProxy
string
=
"xtcp"
SudpProxy
string
=
"sudp"
// authentication method
// authentication method
TokenAuthMethod
string
=
"token"
TokenAuthMethod
string
=
"token"
...
...
models/proto/udp/udp.go
浏览文件 @
47971369
...
@@ -57,11 +57,11 @@ func ForwardUserConn(udpConn *net.UDPConn, readCh <-chan *msg.UdpPacket, sendCh
...
@@ -57,11 +57,11 @@ func ForwardUserConn(udpConn *net.UDPConn, readCh <-chan *msg.UdpPacket, sendCh
for
{
for
{
n
,
remoteAddr
,
err
:=
udpConn
.
ReadFromUDP
(
buf
)
n
,
remoteAddr
,
err
:=
udpConn
.
ReadFromUDP
(
buf
)
if
err
!=
nil
{
if
err
!=
nil
{
udpConn
.
Close
()
return
return
}
}
// buf[:n] will be encoded to string, so the bytes can be reused
// buf[:n] will be encoded to string, so the bytes can be reused
udpMsg
:=
NewUdpPacket
(
buf
[
:
n
],
nil
,
remoteAddr
)
udpMsg
:=
NewUdpPacket
(
buf
[
:
n
],
nil
,
remoteAddr
)
select
{
select
{
case
sendCh
<-
udpMsg
:
case
sendCh
<-
udpMsg
:
default
:
default
:
...
...
server/proxy/proxy.go
浏览文件 @
47971369
...
@@ -219,6 +219,11 @@ func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.Reso
...
@@ -219,6 +219,11 @@ func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.Reso
BaseProxy
:
&
basePxy
,
BaseProxy
:
&
basePxy
,
cfg
:
cfg
,
cfg
:
cfg
,
}
}
case
*
config
.
SudpProxyConf
:
pxy
=
&
SudpProxy
{
BaseProxy
:
&
basePxy
,
cfg
:
cfg
,
}
default
:
default
:
return
pxy
,
fmt
.
Errorf
(
"proxy type not support"
)
return
pxy
,
fmt
.
Errorf
(
"proxy type not support"
)
}
}
...
...
server/proxy/sudp.go
0 → 100644
浏览文件 @
47971369
// Copyright 2019 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
proxy
import
(
"github.com/fatedier/frp/models/config"
)
type
SudpProxy
struct
{
*
BaseProxy
cfg
*
config
.
SudpProxyConf
}
func
(
pxy
*
SudpProxy
)
Run
()
(
remoteAddr
string
,
err
error
)
{
xl
:=
pxy
.
xl
listener
,
errRet
:=
pxy
.
rc
.
VisitorManager
.
Listen
(
pxy
.
GetName
(),
pxy
.
cfg
.
Sk
)
if
errRet
!=
nil
{
err
=
errRet
return
}
pxy
.
listeners
=
append
(
pxy
.
listeners
,
listener
)
xl
.
Info
(
"sudp proxy custom listen success"
)
pxy
.
startListenHandler
(
pxy
,
HandleUserTcpConnection
)
return
}
func
(
pxy
*
SudpProxy
)
GetConf
()
config
.
ProxyConf
{
return
pxy
.
cfg
}
func
(
pxy
*
SudpProxy
)
Close
()
{
pxy
.
BaseProxy
.
Close
()
pxy
.
rc
.
VisitorManager
.
CloseListener
(
pxy
.
GetName
())
}
tests/ci/auto_test_frpc.ini
浏览文件 @
47971369
...
@@ -72,6 +72,12 @@ local_port = 10701
...
@@ -72,6 +72,12 @@ local_port = 10701
use_encryption
=
true
use_encryption
=
true
use_compression
=
true
use_compression
=
true
[sudp]
type
=
sudp
sk
=
abcdefg
local_ip
=
127.0.0.1
local_port
=
10702
[web01]
[web01]
type
=
http
type
=
http
local_ip
=
127.0.0.1
local_ip
=
127.0.0.1
...
...
tests/ci/auto_test_frpc_visitor.ini
浏览文件 @
47971369
...
@@ -23,3 +23,12 @@ bind_addr = 127.0.0.1
...
@@ -23,3 +23,12 @@ bind_addr = 127.0.0.1
bind_port
=
10905
bind_port
=
10905
use_encryption
=
true
use_encryption
=
true
use_compression
=
true
use_compression
=
true
[sudp_visitor]
type
=
sudp
role
=
visitor
server_name
=
sudp
sk
=
abcdefg
bind_addr
=
127.0.0.1
bind_port
=
10816
tests/ci/normal_test.go
浏览文件 @
47971369
...
@@ -118,6 +118,16 @@ func TestStcp(t *testing.T) {
...
@@ -118,6 +118,16 @@ func TestStcp(t *testing.T) {
}
}
}
}
func
TestSudp
(
t
*
testing
.
T
)
{
assert
:=
assert
.
New
(
t
)
// Normal
addr
:=
fmt
.
Sprintf
(
"127.0.0.1:%d"
,
consts
.
TEST_SUDP_FRP_PORT
)
res
,
err
:=
util
.
SendUdpMsg
(
addr
,
consts
.
TEST_SUDP_ECHO_STR
)
assert
.
NoError
(
err
)
assert
.
Equal
(
consts
.
TEST_SUDP_ECHO_STR
,
res
)
}
func
TestHttp
(
t
*
testing
.
T
)
{
func
TestHttp
(
t
*
testing
.
T
)
{
assert
:=
assert
.
New
(
t
)
assert
:=
assert
.
New
(
t
)
// web01
// web01
...
...
tests/consts/consts.go
浏览文件 @
47971369
...
@@ -46,6 +46,9 @@ var (
...
@@ -46,6 +46,9 @@ var (
TEST_STCP_EC_FRP_PORT
int
=
10905
TEST_STCP_EC_FRP_PORT
int
=
10905
TEST_STCP_ECHO_STR
string
=
"stcp type:"
+
TEST_STR
TEST_STCP_ECHO_STR
string
=
"stcp type:"
+
TEST_STR
TEST_SUDP_FRP_PORT
int
=
10816
TEST_SUDP_ECHO_STR
string
=
"sudp type:"
+
TEST_STR
ProxyTcpPortNotAllowed
string
=
"tcp_port_not_allowed"
ProxyTcpPortNotAllowed
string
=
"tcp_port_not_allowed"
ProxyTcpPortUnavailable
string
=
"tcp_port_unavailable"
ProxyTcpPortUnavailable
string
=
"tcp_port_unavailable"
ProxyTcpPortNormal
string
=
"tcp_port_normal"
ProxyTcpPortNormal
string
=
"tcp_port_normal"
...
...
tests/util/util.go
浏览文件 @
47971369
...
@@ -71,6 +71,11 @@ func GetProxyStatus(statusAddr string, user string, passwd string, name string)
...
@@ -71,6 +71,11 @@ func GetProxyStatus(statusAddr string, user string, passwd string, name string)
return
&
s
,
nil
return
&
s
,
nil
}
}
}
}
for
_
,
s
:=
range
allStatus
.
Sudp
{
if
s
.
Name
==
name
{
return
&
s
,
nil
}
}
return
status
,
errors
.
New
(
"no proxy status found"
)
return
status
,
errors
.
New
(
"no proxy status found"
)
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录