Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
企猫商务
frp
提交
2ba84d37
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 搜索 >>
提交
2ba84d37
编写于
4月 06, 2016
作者:
F
fatedier
浏览文件
操作
浏览文件
下载
差异文件
Release v0.3.0
Release v0.3.0
上级
90349a48
6a0d6035
变更
20
隐藏空白更改
内联
并排
Showing
20 changed file
with
526 addition
and
295 deletion
+526
-295
.travis.yml
.travis.yml
+1
-1
Dockerfile
Dockerfile
+2
-2
README.md
README.md
+13
-4
README_zh.md
README_zh.md
+40
-0
conf/frpc.ini
conf/frpc.ini
+4
-1
conf/frps.ini
conf/frps.ini
+2
-2
doc/quick_start_en.md
doc/quick_start_en.md
+5
-2
doc/quick_start_zh.md
doc/quick_start_zh.md
+5
-2
src/frp/cmd/frpc/control.go
src/frp/cmd/frpc/control.go
+86
-69
src/frp/cmd/frps/control.go
src/frp/cmd/frps/control.go
+144
-112
src/frp/models/client/client.go
src/frp/models/client/client.go
+21
-9
src/frp/models/client/config.go
src/frp/models/client/config.go
+20
-4
src/frp/models/consts/consts.go
src/frp/models/consts/consts.go
+8
-13
src/frp/models/msg/msg.go
src/frp/models/msg/msg.go
+11
-10
src/frp/models/server/config.go
src/frp/models/server/config.go
+2
-2
src/frp/models/server/server.go
src/frp/models/server/server.go
+27
-19
src/frp/utils/conn/conn.go
src/frp/utils/conn/conn.go
+93
-1
src/frp/utils/pcrypto/pcrypto.go
src/frp/utils/pcrypto/pcrypto.go
+36
-22
src/frp/utils/pcrypto/pcrypto_test.go
src/frp/utils/pcrypto/pcrypto_test.go
+5
-19
src/frp/utils/version/version.go
src/frp/utils/version/version.go
+1
-1
未找到文件。
.travis.yml
浏览文件 @
2ba84d37
...
...
@@ -3,7 +3,7 @@ language: go
go
:
-
1.4.2
-
1.5.
1
-
1.5.
3
install
:
-
make
...
...
Dockerfile
浏览文件 @
2ba84d37
...
...
@@ -2,7 +2,7 @@ FROM golang:1.5
MAINTAINER
fatedier
RUN
echo
"[common]
\n
bind_addr = 0.0.0.0
\n
bind_port = 7000
\n
[
wiki
]
\n
passwd = 123
\n
bind_addr = 0.0.0.0
\n
listen_port = 80"
>
/usr/share/frps.ini
RUN
echo
"[common]
\n
bind_addr = 0.0.0.0
\n
bind_port = 7000
\n
[
test
]
\n
passwd = 123
\n
bind_addr = 0.0.0.0
\n
listen_port = 80"
>
/usr/share/frps.ini
ADD
./ /usr/share/frp/
...
...
@@ -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"]
README.md
浏览文件 @
2ba84d37
...
...
@@ -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
...
...
@@ -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
)
README_zh.md
0 → 100644
浏览文件 @
2ba84d37
# 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
)
conf/frpc.ini
浏览文件 @
2ba84d37
...
...
@@ -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
conf/frps.ini
浏览文件 @
2ba84d37
...
...
@@ -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
doc/quick_start_en.md
浏览文件 @
2ba84d37
...
...
@@ -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
...
...
@@ -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
```
doc/quick_start_zh.md
浏览文件 @
2ba84d37
...
...
@@ -42,7 +42,7 @@ log_level = info
# test 为代理的自定义名称,可以有多个,不能重复,和frpc中名称对应
[test]
passwd
=
123
auth_token
=
123
bind_addr
=
0.0.0.0
# 最后将通过此端口访问后端服务
listen_port
=
6000
...
...
@@ -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
```
src/frp/cmd/frpc/control.go
浏览文件 @
2ba84d37
...
...
@@ -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
sleep
Time
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
delay
Time
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
sleep
Time
<
60
{
sleepTime
=
sleep
Time
*
2
if
delay
Time
<
60
{
delayTime
=
delay
Time
*
2
}
time
.
Sleep
(
sleep
Time
*
time
.
Second
)
time
.
Sleep
(
delay
Time
*
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
}
c
lientCtlRes
:=
&
msg
.
ClientCt
lRes
{}
if
err
:=
json
.
Unmarshal
([]
byte
(
content
),
clientC
tlRes
);
err
!=
nil
{
log
.
Warn
(
"P
arse err: %v : %s"
,
err
,
content
)
c
tlRes
:=
&
msg
.
Contro
lRes
{}
if
err
:=
json
.
Unmarshal
([]
byte
(
buf
),
&
c
tlRes
);
err
!=
nil
{
log
.
Warn
(
"P
roxyName [%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
}
}
}
...
...
@@ -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
"
)
...
...
@@ -115,53 +154,31 @@ func loginToServer(cli *client.ProxyClient) (c *conn.Conn, err error) {
}
log
.
Debug
(
"ProxyName [%s], read [%s]"
,
cli
.
Name
,
res
)
c
lientCtlRes
:=
&
msg
.
ClientCt
lRes
{}
if
err
=
json
.
Unmarshal
([]
byte
(
res
),
&
c
lientC
tlRes
);
err
!=
nil
{
c
tlRes
:=
&
msg
.
Contro
lRes
{}
if
err
=
json
.
Unmarshal
([]
byte
(
res
),
&
ctlRes
);
err
!=
nil
{
log
.
Error
(
"ProxyName [%s], format server response error, %v"
,
cli
.
Name
,
err
)
return
}
if
c
lientC
tlRes
.
Code
!=
0
{
log
.
Error
(
"ProxyName [%s], start proxy error, %s"
,
cli
.
Name
,
c
lientC
tlRes
.
Msg
)
return
c
,
fmt
.
Errorf
(
"%s"
,
c
lientC
tlRes
.
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
}
...
...
src/frp/cmd/frps/control.go
浏览文件 @
2ba84d37
...
...
@@ -25,6 +25,7 @@ import (
"frp/models/server"
"frp/utils/conn"
"frp/utils/log"
"frp/utils/pcrypto"
)
func
ProcessControlConn
(
l
*
conn
.
Listener
)
{
...
...
@@ -33,87 +34,162 @@ func ProcessControlConn(l *conn.Listener) {
if
err
!=
nil
{
return
}
log
.
Debug
(
"Get
one new con
n, %v"
,
c
.
GetRemoteAddr
())
log
.
Debug
(
"Get
new connectio
n, %v"
,
c
.
GetRemoteAddr
())
go
controlWorker
(
c
)
}
}
// connection from every client and server
func
controlWorker
(
c
*
conn
.
Conn
)
{
// the first message is from client to server
// if error, close connection
res
,
err
:=
c
.
ReadLine
()
// if login message type is NewWorkConn, don't close this connection
var
closeFlag
bool
=
true
var
s
*
server
.
ProxyServer
defer
func
()
{
if
closeFlag
{
c
.
Close
()
if
s
!=
nil
{
s
.
Close
()
}
}
}()
// get login message
buf
,
err
:=
c
.
ReadLine
()
if
err
!=
nil
{
log
.
Warn
(
"Read error, %v"
,
err
)
return
}
log
.
Debug
(
"
get: %s"
,
res
)
log
.
Debug
(
"
Get msg from frpc: %s"
,
buf
)
clientCtlReq
:=
&
msg
.
ClientCtlReq
{}
clientCtlRes
:=
&
msg
.
ClientCtlRes
{}
if
err
:=
json
.
Unmarshal
([]
byte
(
res
),
&
clientCtlReq
);
err
!=
nil
{
log
.
Warn
(
"Parse err: %v : %s"
,
err
,
res
)
cliReq
:=
&
msg
.
ControlReq
{}
if
err
:=
json
.
Unmarshal
([]
byte
(
buf
),
&
cliReq
);
err
!=
nil
{
log
.
Warn
(
"Parse msg from frpc error: %v : %s"
,
err
,
buf
)
return
}
// check
succ
,
info
,
needRes
:=
checkProxy
(
clientCtlReq
,
c
)
if
!
succ
{
clientCtlRes
.
Code
=
1
clientCtlRes
.
Msg
=
info
// do login when type is NewCtlConn or NewWorkConn
ret
,
info
:=
doLogin
(
cliReq
,
c
)
s
,
ok
:=
server
.
ProxyServers
[
cliReq
.
ProxyName
]
if
!
ok
{
log
.
Warn
(
"ProxyName [%s] is not exist"
,
cliReq
.
ProxyName
)
return
}
if
needRes
{
defer
c
.
Close
()
buf
,
_
:=
json
.
Marshal
(
clientCtlRes
)
err
=
c
.
Write
(
string
(
buf
)
+
"
\n
"
)
// if login type is NewWorkConn, nothing will be send to frpc
if
cliReq
.
Type
!=
consts
.
NewWorkConn
{
cliRes
:=
&
msg
.
ControlRes
{
Type
:
consts
.
NewCtlConnRes
,
Code
:
ret
,
Msg
:
info
,
}
byteBuf
,
_
:=
json
.
Marshal
(
cliRes
)
err
=
c
.
Write
(
string
(
byteBuf
)
+
"
\n
"
)
if
err
!=
nil
{
log
.
Warn
(
"
Write error, %v"
,
err
)
log
.
Warn
(
"
ProxyName [%s], write to client error, proxy exit"
,
s
.
Name
)
time
.
Sleep
(
1
*
time
.
Second
)
return
}
}
else
{
// work conn, just return
closeFlag
=
false
return
}
// other messages is from server to client
s
,
ok
:=
server
.
ProxyServers
[
clientCtlReq
.
ProxyName
]
if
!
ok
{
log
.
Warn
(
"ProxyName [%s] is not exist"
,
clientCtlReq
.
ProxyName
)
return
}
// create a channel for sending messages
msgSendChan
:=
make
(
chan
interface
{},
1024
)
go
msgSender
(
s
,
c
,
msgSendChan
)
go
noticeUserConn
(
s
,
msgSendChan
)
//
read control msg from client
go
readControlMsgFromClient
(
s
,
c
)
//
loop for reading control messages from frpc and deal with different types
msgReader
(
s
,
c
,
msgSendChan
)
serverCtlReq
:=
&
msg
.
ClientCtlReq
{}
serverCtlReq
.
Type
=
consts
.
WorkConn
close
(
msgSendChan
)
log
.
Info
(
"ProxyName [%s], I'm dead!"
,
s
.
Name
)
return
}
// when frps get one new user connection, send NoticeUserConn message to frpc and accept one new WorkConn later
func
noticeUserConn
(
s
*
server
.
ProxyServer
,
msgSendChan
chan
interface
{})
{
for
{
closeFlag
:=
s
.
WaitUserConn
()
if
closeFlag
{
log
.
Debug
(
"ProxyName [%s], goroutine for
deal
ing user conn is closed"
,
s
.
Name
)
log
.
Debug
(
"ProxyName [%s], goroutine for
notic
ing user conn is closed"
,
s
.
Name
)
break
}
buf
,
_
:=
json
.
Marshal
(
serverCtlReq
)
err
=
c
.
Write
(
string
(
buf
)
+
"
\n
"
)
notice
:=
&
msg
.
ControlRes
{
Type
:
consts
.
NoticeUserConn
,
}
msgSendChan
<-
notice
log
.
Debug
(
"ProxyName [%s], notice client to add work conn"
,
s
.
Name
)
}
}
// loop for reading messages from frpc after control connection is established
func
msgReader
(
s
*
server
.
ProxyServer
,
c
*
conn
.
Conn
,
msgSendChan
chan
interface
{})
error
{
// for heartbeat
var
heartbeatTimeout
bool
=
false
timer
:=
time
.
AfterFunc
(
time
.
Duration
(
server
.
HeartBeatTimeout
)
*
time
.
Second
,
func
()
{
heartbeatTimeout
=
true
s
.
Close
()
c
.
Close
()
log
.
Error
(
"ProxyName [%s], client heartbeat timeout"
,
s
.
Name
)
})
defer
timer
.
Stop
()
for
{
buf
,
err
:=
c
.
ReadLine
()
if
err
!=
nil
{
log
.
Warn
(
"ProxyName [%s], write to client error, proxy exit"
,
s
.
Name
)
s
.
Close
()
return
if
err
==
io
.
EOF
{
log
.
Warn
(
"ProxyName [%s], client is dead!"
,
s
.
Name
)
return
err
}
else
if
c
==
nil
||
c
.
IsClosed
()
{
log
.
Warn
(
"ProxyName [%s], client connection is closed"
,
s
.
Name
)
return
err
}
log
.
Warn
(
"ProxyName [%s], read error: %v"
,
s
.
Name
,
err
)
continue
}
cliReq
:=
&
msg
.
ControlReq
{}
if
err
:=
json
.
Unmarshal
([]
byte
(
buf
),
&
cliReq
);
err
!=
nil
{
log
.
Warn
(
"ProxyName [%s], parse msg from frpc error: %v : %s"
,
s
.
Name
,
err
,
buf
)
continue
}
log
.
Debug
(
"ProxyName [%s], write to client to add work conn success"
,
s
.
Name
)
switch
cliReq
.
Type
{
case
consts
.
HeartbeatReq
:
log
.
Debug
(
"ProxyName [%s], get heartbeat"
,
s
.
Name
)
timer
.
Reset
(
time
.
Duration
(
server
.
HeartBeatTimeout
)
*
time
.
Second
)
heartbeatRes
:=
msg
.
ControlRes
{
Type
:
consts
.
HeartbeatRes
,
}
msgSendChan
<-
heartbeatRes
default
:
log
.
Warn
(
"ProxyName [%s}, unsupport msgType [%d]"
,
s
.
Name
,
cliReq
.
Type
)
}
}
return
nil
}
log
.
Info
(
"ProxyName [%s], I'm dead!"
,
s
.
Name
)
return
// loop for sending messages from channel to frpc
func
msgSender
(
s
*
server
.
ProxyServer
,
c
*
conn
.
Conn
,
msgSendChan
chan
interface
{})
{
for
{
msg
,
ok
:=
<-
msgSendChan
if
!
ok
{
break
}
buf
,
_
:=
json
.
Marshal
(
msg
)
err
:=
c
.
Write
(
string
(
buf
)
+
"
\n
"
)
if
err
!=
nil
{
log
.
Warn
(
"ProxyName [%s], write to client error, proxy exit"
,
s
.
Name
)
s
.
Close
()
break
}
}
}
func
checkProxy
(
req
*
msg
.
ClientCtlReq
,
c
*
conn
.
Conn
)
(
succ
bool
,
info
string
,
needRes
bool
)
{
succ
=
false
needRes
=
true
// if success, ret equals 0, otherwise greater than 0
func
doLogin
(
req
*
msg
.
ControlReq
,
c
*
conn
.
Conn
)
(
ret
int64
,
info
string
)
{
ret
=
1
// check if proxy name exist
s
,
ok
:=
server
.
ProxyServers
[
req
.
ProxyName
]
if
!
ok
{
...
...
@@ -122,97 +198,53 @@ func checkProxy(req *msg.ClientCtlReq, c *conn.Conn) (succ bool, info string, ne
return
}
// check password
if
req
.
Passwd
!=
s
.
Passwd
{
info
=
fmt
.
Sprintf
(
"ProxyName [%s], password is not correct"
,
req
.
ProxyName
)
// check authKey
nowTime
:=
time
.
Now
()
.
Unix
()
authKey
:=
pcrypto
.
GetAuthKey
(
req
.
ProxyName
+
s
.
AuthToken
+
fmt
.
Sprintf
(
"%d"
,
req
.
Timestamp
))
// authKey avaiable in 15 minutes
if
nowTime
-
req
.
Timestamp
>
15
*
60
{
info
=
fmt
.
Sprintf
(
"ProxyName [%s], authorization timeout"
,
req
.
ProxyName
)
log
.
Warn
(
info
)
return
}
else
if
req
.
AuthKey
!=
authKey
{
info
=
fmt
.
Sprintf
(
"ProxyName [%s], authorization failed"
,
req
.
ProxyName
)
log
.
Warn
(
info
)
return
}
// control conn
if
req
.
Type
==
consts
.
CtlConn
{
if
s
.
Status
!=
consts
.
Idle
{
if
req
.
Type
==
consts
.
New
CtlConn
{
if
s
.
Status
==
consts
.
Working
{
info
=
fmt
.
Sprintf
(
"ProxyName [%s], already in use"
,
req
.
ProxyName
)
log
.
Warn
(
info
)
return
}
// start proxy and listen for user conn, no block
// set infomations from frpc
s
.
UseEncryption
=
req
.
UseEncryption
// start proxy and listen for user connections, no block
err
:=
s
.
Start
()
if
err
!=
nil
{
info
=
fmt
.
Sprintf
(
"ProxyName [%s], start proxy error: %v"
,
req
.
ProxyName
,
err
.
Error
()
)
info
=
fmt
.
Sprintf
(
"ProxyName [%s], start proxy error: %v"
,
req
.
ProxyName
,
err
)
log
.
Warn
(
info
)
return
}
log
.
Info
(
"ProxyName [%s], start proxy success"
,
req
.
ProxyName
)
}
else
if
req
.
Type
==
consts
.
WorkConn
{
}
else
if
req
.
Type
==
consts
.
New
WorkConn
{
// work conn
needRes
=
false
if
s
.
Status
!=
consts
.
Working
{
log
.
Warn
(
"ProxyName [%s], is not working when it gets one new work conn"
,
req
.
ProxyName
)
log
.
Warn
(
"ProxyName [%s], is not working when it gets one new work conn
nection
"
,
req
.
ProxyName
)
return
}
s
.
GetNewCli
Conn
(
c
)
// the connection will close after join over
s
.
RecvNewWork
Conn
(
c
)
}
else
{
info
=
fmt
.
Sprintf
(
"
ProxyName [%s], type [%d] unsupport"
,
req
.
ProxyName
,
req
.
Type
)
log
.
Warn
(
info
)
info
=
fmt
.
Sprintf
(
"
Unsupport login message type [%d]"
,
req
.
Type
)
log
.
Warn
(
"Unsupport login message type [%d]"
,
req
.
Type
)
return
}
succ
=
true
ret
=
0
return
}
func
readControlMsgFromClient
(
s
*
server
.
ProxyServer
,
c
*
conn
.
Conn
)
{
isContinueRead
:=
true
f
:=
func
()
{
isContinueRead
=
false
s
.
Close
()
log
.
Error
(
"ProxyName [%s], client heartbeat timeout"
,
s
.
Name
)
}
timer
:=
time
.
AfterFunc
(
time
.
Duration
(
server
.
HeartBeatTimeout
)
*
time
.
Second
,
f
)
defer
timer
.
Stop
()
for
isContinueRead
{
content
,
err
:=
c
.
ReadLine
()
if
err
!=
nil
{
if
err
==
io
.
EOF
{
log
.
Warn
(
"ProxyName [%s], client is dead!"
,
s
.
Name
)
s
.
Close
()
break
}
else
if
nil
==
c
||
c
.
IsClosed
()
{
log
.
Warn
(
"ProxyName [%s], client connection is closed"
,
s
.
Name
)
break
}
log
.
Error
(
"ProxyName [%s], read error: %v"
,
s
.
Name
,
err
)
continue
}
clientCtlReq
:=
&
msg
.
ClientCtlReq
{}
if
err
:=
json
.
Unmarshal
([]
byte
(
content
),
clientCtlReq
);
err
!=
nil
{
log
.
Warn
(
"Parse err: %v : %s"
,
err
,
content
)
continue
}
if
consts
.
CSHeartBeatReq
==
clientCtlReq
.
Type
{
log
.
Debug
(
"ProxyName [%s], get heartbeat"
,
s
.
Name
)
timer
.
Reset
(
time
.
Duration
(
server
.
HeartBeatTimeout
)
*
time
.
Second
)
clientCtlRes
:=
&
msg
.
ClientCtlRes
{}
clientCtlRes
.
GeneralRes
.
Code
=
consts
.
SCHeartBeatRes
response
,
err
:=
json
.
Marshal
(
clientCtlRes
)
if
err
!=
nil
{
log
.
Warn
(
"Serialize ClientCtlRes err! err: %v"
,
err
)
continue
}
err
=
c
.
Write
(
string
(
response
)
+
"
\n
"
)
if
err
!=
nil
{
log
.
Error
(
"Send heartbeat response to client failed! Err:%v"
,
err
)
continue
}
}
}
}
src/frp/models/client/client.go
浏览文件 @
2ba84d37
...
...
@@ -16,18 +16,22 @@ package client
import
(
"encoding/json"
"fmt"
"time"
"frp/models/consts"
"frp/models/msg"
"frp/utils/conn"
"frp/utils/log"
"frp/utils/pcrypto"
)
type
ProxyClient
struct
{
Name
string
Passwd
string
LocalIp
string
LocalPort
int64
Name
string
AuthToken
string
LocalIp
string
LocalPort
int64
UseEncryption
bool
}
func
(
p
*
ProxyClient
)
GetLocalConn
()
(
c
*
conn
.
Conn
,
err
error
)
{
...
...
@@ -51,10 +55,13 @@ func (p *ProxyClient) GetRemoteConn(addr string, port int64) (c *conn.Conn, err
return
}
req
:=
&
msg
.
ClientCtlReq
{
Type
:
consts
.
WorkConn
,
nowTime
:=
time
.
Now
()
.
Unix
()
authKey
:=
pcrypto
.
GetAuthKey
(
p
.
Name
+
p
.
AuthToken
+
fmt
.
Sprintf
(
"%d"
,
nowTime
))
req
:=
&
msg
.
ControlReq
{
Type
:
consts
.
NewWorkConn
,
ProxyName
:
p
.
Name
,
Passwd
:
p
.
Passwd
,
AuthKey
:
authKey
,
Timestamp
:
nowTime
,
}
buf
,
_
:=
json
.
Marshal
(
req
)
...
...
@@ -79,8 +86,13 @@ func (p *ProxyClient) StartTunnel(serverAddr string, serverPort int64) (err erro
}
// l means local, r means remote
log
.
Debug
(
"Join two conns, (l[%s] r[%s]) (l[%s] r[%s])"
,
localConn
.
GetLocalAddr
(),
localConn
.
GetRemoteAddr
(),
log
.
Debug
(
"Join two conn
ection
s, (l[%s] r[%s]) (l[%s] r[%s])"
,
localConn
.
GetLocalAddr
(),
localConn
.
GetRemoteAddr
(),
remoteConn
.
GetLocalAddr
(),
remoteConn
.
GetRemoteAddr
())
go
conn
.
Join
(
localConn
,
remoteConn
)
if
p
.
UseEncryption
{
go
conn
.
JoinMore
(
localConn
,
remoteConn
,
p
.
AuthToken
)
}
else
{
go
conn
.
Join
(
localConn
,
remoteConn
)
}
return
nil
}
src/frp/models/client/config.go
浏览文件 @
2ba84d37
...
...
@@ -69,23 +69,32 @@ func LoadConf(confFile string) (err error) {
LogLevel
=
tmpStr
}
var
authToken
string
tmpStr
,
ok
=
conf
.
Get
(
"common"
,
"auth_token"
)
if
ok
{
authToken
=
tmpStr
}
else
{
return
fmt
.
Errorf
(
"auth_token not found"
)
}
// proxies
for
name
,
section
:=
range
conf
{
if
name
!=
"common"
{
proxyClient
:=
&
ProxyClient
{}
// name
proxyClient
.
Name
=
name
proxyClient
.
Passwd
,
ok
=
section
[
"passwd"
]
if
!
ok
{
return
fmt
.
Errorf
(
"Parse ini file error: proxy [%s] no passwd found"
,
proxyClient
.
Name
)
}
// auth_token
proxyClient
.
AuthToken
=
authToken
// local_ip
proxyClient
.
LocalIp
,
ok
=
section
[
"local_ip"
]
if
!
ok
{
// use 127.0.0.1 as default
proxyClient
.
LocalIp
=
"127.0.0.1"
}
// local_port
portStr
,
ok
:=
section
[
"local_port"
]
if
ok
{
proxyClient
.
LocalPort
,
err
=
strconv
.
ParseInt
(
portStr
,
10
,
64
)
...
...
@@ -96,6 +105,13 @@ func LoadConf(confFile string) (err error) {
return
fmt
.
Errorf
(
"Parse ini file error: proxy [%s] local_port not found"
,
proxyClient
.
Name
)
}
// use_encryption
proxyClient
.
UseEncryption
=
false
useEncryptionStr
,
ok
:=
section
[
"use_encryption"
]
if
ok
&&
useEncryptionStr
==
"true"
{
proxyClient
.
UseEncryption
=
true
}
ProxyClients
[
proxyClient
.
Name
]
=
proxyClient
}
}
...
...
src/frp/models/consts/consts.go
浏览文件 @
2ba84d37
...
...
@@ -18,20 +18,15 @@ package consts
const
(
Idle
=
iota
Working
Closed
)
//
connection
type
//
msg
type
const
(
CtlConn
=
iota
WorkConn
)
// msg from client to server
const
(
CSHeartBeatReq
=
1
)
// msg from server to client
const
(
SCHeartBeatRes
=
100
NewCtlConn
=
iota
NewWorkConn
NoticeUserConn
NewCtlConnRes
HeartbeatReq
HeartbeatRes
)
src/frp/models/msg/msg.go
浏览文件 @
2ba84d37
...
...
@@ -19,16 +19,17 @@ type GeneralRes struct {
Msg
string
`json:"msg"`
}
type
ClientCtlReq
struct
{
Type
int64
`json:"type"`
ProxyName
string
`json:"proxy_name"`
Passwd
string
`json:"passwd"`
// messages between control connection of frpc and frps
type
ControlReq
struct
{
Type
int64
`json:"type"`
ProxyName
string
`json:"proxy_name,omitempty"`
AuthKey
string
`json:"auth_key, omitempty"`
UseEncryption
bool
`json:"use_encryption, omitempty"`
Timestamp
int64
`json:"timestamp, omitempty"`
}
type
ClientCtlRes
struct
{
GeneralRes
}
type
ServerCtlReq
struct
{
Type
int64
`json:"type"`
type
ControlRes
struct
{
Type
int64
`json:"type"`
Code
int64
`json:"code"`
Msg
string
`json:"msg"`
}
src/frp/models/server/config.go
浏览文件 @
2ba84d37
...
...
@@ -75,9 +75,9 @@ func LoadConf(confFile string) (err error) {
proxyServer
:=
&
ProxyServer
{}
proxyServer
.
Name
=
name
proxyServer
.
Passwd
,
ok
=
section
[
"passwd
"
]
proxyServer
.
AuthToken
,
ok
=
section
[
"auth_token
"
]
if
!
ok
{
return
fmt
.
Errorf
(
"Parse ini file error: proxy [%s] no
passwd
found"
,
proxyServer
.
Name
)
return
fmt
.
Errorf
(
"Parse ini file error: proxy [%s] no
auth_token
found"
,
proxyServer
.
Name
)
}
proxyServer
.
BindAddr
,
ok
=
section
[
"bind_addr"
]
...
...
src/frp/models/server/server.go
浏览文件 @
2ba84d37
...
...
@@ -25,22 +25,23 @@ import (
)
type
ProxyServer
struct
{
Name
string
Passwd
string
BindAddr
string
ListenPort
int64
Status
int64
Name
string
AuthToken
string
UseEncryption
bool
BindAddr
string
ListenPort
int64
Status
int64
listener
*
conn
.
Listener
// accept new connection from remote users
ctlMsgChan
chan
int64
// every time accept a new user conn, put "1" to the channel
cliConnChan
chan
*
conn
.
Conn
// get client
conns from control goroutine
workConnChan
chan
*
conn
.
Conn
// get new work
conns from control goroutine
userConnList
*
list
.
List
// store user conns
mutex
sync
.
Mutex
}
func
(
p
*
ProxyServer
)
Init
()
{
p
.
Status
=
consts
.
Idle
p
.
cli
ConnChan
=
make
(
chan
*
conn
.
Conn
)
p
.
work
ConnChan
=
make
(
chan
*
conn
.
Conn
)
p
.
ctlMsgChan
=
make
(
chan
int64
)
p
.
userConnList
=
list
.
New
()
}
...
...
@@ -109,7 +110,7 @@ func (p *ProxyServer) Start() (err error) {
// start another goroutine for join two conns from client and user
go
func
()
{
for
{
cliConn
,
ok
:=
<-
p
.
cli
ConnChan
workConn
,
ok
:=
<-
p
.
work
ConnChan
if
!
ok
{
return
}
...
...
@@ -122,7 +123,7 @@ func (p *ProxyServer) Start() (err error) {
userConn
=
element
.
Value
.
(
*
conn
.
Conn
)
p
.
userConnList
.
Remove
(
element
)
}
else
{
cli
Conn
.
Close
()
work
Conn
.
Close
()
p
.
Unlock
()
continue
}
...
...
@@ -130,9 +131,14 @@ func (p *ProxyServer) Start() (err error) {
// msg will transfer to another without modifying
// l means local, r means remote
log
.
Debug
(
"Join two conn
s, (l[%s] r[%s]) (l[%s] r[%s])"
,
cliConn
.
GetLocalAddr
(),
cli
Conn
.
GetRemoteAddr
(),
log
.
Debug
(
"Join two conn
ections, (l[%s] r[%s]) (l[%s] r[%s])"
,
workConn
.
GetLocalAddr
(),
work
Conn
.
GetRemoteAddr
(),
userConn
.
GetLocalAddr
(),
userConn
.
GetRemoteAddr
())
go
conn
.
Join
(
cliConn
,
userConn
)
if
p
.
UseEncryption
{
go
conn
.
JoinMore
(
userConn
,
workConn
,
p
.
AuthToken
)
}
else
{
go
conn
.
Join
(
userConn
,
workConn
)
}
}
}()
...
...
@@ -141,13 +147,15 @@ func (p *ProxyServer) Start() (err error) {
func
(
p
*
ProxyServer
)
Close
()
{
p
.
Lock
()
p
.
Status
=
consts
.
Idle
if
p
.
listener
!=
nil
{
p
.
listener
.
Close
()
if
p
.
Status
!=
consts
.
Closed
{
p
.
Status
=
consts
.
Closed
if
p
.
listener
!=
nil
{
p
.
listener
.
Close
()
}
close
(
p
.
ctlMsgChan
)
close
(
p
.
workConnChan
)
p
.
userConnList
=
list
.
New
()
}
close
(
p
.
ctlMsgChan
)
close
(
p
.
cliConnChan
)
p
.
userConnList
=
list
.
New
()
p
.
Unlock
()
}
...
...
@@ -161,6 +169,6 @@ func (p *ProxyServer) WaitUserConn() (closeFlag bool) {
return
}
func
(
p
*
ProxyServer
)
GetNewCli
Conn
(
c
*
conn
.
Conn
)
{
p
.
cli
ConnChan
<-
c
func
(
p
*
ProxyServer
)
RecvNewWork
Conn
(
c
*
conn
.
Conn
)
{
p
.
work
ConnChan
<-
c
}
src/frp/utils/conn/conn.go
浏览文件 @
2ba84d37
...
...
@@ -22,6 +22,7 @@ import (
"sync"
"frp/utils/log"
"frp/utils/pcrypto"
)
type
Listener
struct
{
...
...
@@ -127,6 +128,7 @@ func (c *Conn) ReadLine() (buff string, err error) {
func
(
c
*
Conn
)
Write
(
content
string
)
(
err
error
)
{
_
,
err
=
c
.
TcpConn
.
Write
([]
byte
(
content
))
return
err
}
func
(
c
*
Conn
)
Close
()
{
...
...
@@ -151,7 +153,7 @@ func Join(c1 *Conn, c2 *Conn) {
var
err
error
_
,
err
=
io
.
Copy
(
to
.
TcpConn
,
from
.
TcpConn
)
if
err
!=
nil
{
log
.
Warn
(
"join conns error, %v"
,
err
)
log
.
Warn
(
"join conn
ection
s error, %v"
,
err
)
}
}
...
...
@@ -161,3 +163,93 @@ func Join(c1 *Conn, c2 *Conn) {
wait
.
Wait
()
return
}
// messages from c1 to c2 will be encrypted
// and from c2 to c1 will be decrypted
func
JoinMore
(
c1
*
Conn
,
c2
*
Conn
,
cryptKey
string
)
{
var
wait
sync
.
WaitGroup
encryptPipe
:=
func
(
from
*
Conn
,
to
*
Conn
,
key
string
)
{
defer
from
.
Close
()
defer
to
.
Close
()
defer
wait
.
Done
()
// we don't care about errors here
PipeEncrypt
(
from
.
TcpConn
,
to
.
TcpConn
,
key
)
}
decryptPipe
:=
func
(
to
*
Conn
,
from
*
Conn
,
key
string
)
{
defer
from
.
Close
()
defer
to
.
Close
()
defer
wait
.
Done
()
// we don't care about errors here
PipeDecrypt
(
to
.
TcpConn
,
from
.
TcpConn
,
key
)
}
wait
.
Add
(
2
)
go
encryptPipe
(
c1
,
c2
,
cryptKey
)
go
decryptPipe
(
c2
,
c1
,
cryptKey
)
wait
.
Wait
()
log
.
Debug
(
"One tunnel stopped"
)
return
}
// decrypt msg from reader, then write into writer
func
PipeDecrypt
(
r
net
.
Conn
,
w
net
.
Conn
,
key
string
)
error
{
laes
:=
new
(
pcrypto
.
Pcrypto
)
if
err
:=
laes
.
Init
([]
byte
(
key
));
err
!=
nil
{
log
.
Error
(
"Pcrypto Init error: %v"
,
err
)
return
fmt
.
Errorf
(
"Pcrypto Init error: %v"
,
err
)
}
nreader
:=
bufio
.
NewReader
(
r
)
for
{
buf
,
err
:=
nreader
.
ReadBytes
(
'\n'
)
if
err
!=
nil
{
return
err
}
res
,
err
:=
laes
.
Decrypt
(
buf
)
if
err
!=
nil
{
log
.
Error
(
"Decrypt [%s] error, %v"
,
string
(
buf
),
err
)
return
fmt
.
Errorf
(
"Decrypt [%s] error: %v"
,
string
(
buf
),
err
)
}
_
,
err
=
w
.
Write
(
res
)
if
err
!=
nil
{
return
err
}
}
return
nil
}
// recvive msg from reader, then encrypt msg into write
func
PipeEncrypt
(
r
net
.
Conn
,
w
net
.
Conn
,
key
string
)
error
{
laes
:=
new
(
pcrypto
.
Pcrypto
)
if
err
:=
laes
.
Init
([]
byte
(
key
));
err
!=
nil
{
log
.
Error
(
"Pcrypto Init error: %v"
,
err
)
return
fmt
.
Errorf
(
"Pcrypto Init error: %v"
,
err
)
}
nreader
:=
bufio
.
NewReader
(
r
)
buf
:=
make
([]
byte
,
10
*
1024
)
for
{
n
,
err
:=
nreader
.
Read
(
buf
)
if
err
!=
nil
{
return
err
}
res
,
err
:=
laes
.
Encrypt
(
buf
[
:
n
])
if
err
!=
nil
{
log
.
Error
(
"Encrypt error: %v"
,
err
)
return
fmt
.
Errorf
(
"Encrypt error: %v"
,
err
)
}
res
=
append
(
res
,
'\n'
)
_
,
err
=
w
.
Write
(
res
)
if
err
!=
nil
{
return
err
}
}
return
nil
}
src/frp/utils/pcrypto/pcrypto.go
浏览文件 @
2ba84d37
...
...
@@ -19,6 +19,7 @@ import (
"compress/gzip"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"errors"
...
...
@@ -33,43 +34,40 @@ type Pcrypto struct {
func
(
pc
*
Pcrypto
)
Init
(
key
[]
byte
)
error
{
var
err
error
pc
.
pkey
=
P
KCS7Padding
(
key
,
aes
.
BlockSize
)
pc
.
pkey
=
p
KCS7Padding
(
key
,
aes
.
BlockSize
)
pc
.
paes
,
err
=
aes
.
NewCipher
(
pc
.
pkey
)
return
err
}
func
(
pc
*
Pcrypto
)
Encrypto
(
src
[]
byte
)
([]
byte
,
error
)
{
// aes
src
=
PKCS7Padding
(
src
,
aes
.
BlockSize
)
blockMode
:=
cipher
.
NewCBCEncrypter
(
pc
.
paes
,
pc
.
pkey
)
crypted
:=
make
([]
byte
,
len
(
src
))
blockMode
.
CryptBlocks
(
crypted
,
src
)
func
(
pc
*
Pcrypto
)
Encrypt
(
src
[]
byte
)
([]
byte
,
error
)
{
// gzip
var
zbuf
bytes
.
Buffer
zwr
:=
gzip
.
NewWriter
(
&
zbuf
)
zwr
,
err
:=
gzip
.
NewWriterLevel
(
&
zbuf
,
-
1
)
if
err
!=
nil
{
return
nil
,
err
}
defer
zwr
.
Close
()
zwr
.
Write
(
crypted
)
zwr
.
Write
(
src
)
zwr
.
Flush
()
// aes
src
=
pKCS7Padding
(
zbuf
.
Bytes
(),
aes
.
BlockSize
)
blockMode
:=
cipher
.
NewCBCEncrypter
(
pc
.
paes
,
pc
.
pkey
)
crypted
:=
make
([]
byte
,
len
(
src
))
blockMode
.
CryptBlocks
(
crypted
,
src
)
// base64
return
[]
byte
(
base64
.
StdEncoding
.
EncodeToString
(
zbuf
.
Bytes
()
)),
nil
return
[]
byte
(
base64
.
StdEncoding
.
EncodeToString
(
crypted
)),
nil
}
func
(
pc
*
Pcrypto
)
Decrypt
o
(
str
[]
byte
)
([]
byte
,
error
)
{
func
(
pc
*
Pcrypto
)
Decrypt
(
str
[]
byte
)
([]
byte
,
error
)
{
// base64
data
,
err
:=
base64
.
StdEncoding
.
DecodeString
(
string
(
str
))
if
err
!=
nil
{
return
nil
,
err
}
// gunzip
zbuf
:=
bytes
.
NewBuffer
(
data
)
zrd
,
_
:=
gzip
.
NewReader
(
zbuf
)
defer
zrd
.
Close
()
data
,
_
=
ioutil
.
ReadAll
(
zrd
)
// aes
decryptText
,
err
:=
hex
.
DecodeString
(
fmt
.
Sprintf
(
"%x"
,
data
))
if
err
!=
nil
{
...
...
@@ -83,19 +81,35 @@ func (pc *Pcrypto) Decrypto(str []byte) ([]byte, error) {
blockMode
:=
cipher
.
NewCBCDecrypter
(
pc
.
paes
,
pc
.
pkey
)
blockMode
.
CryptBlocks
(
decryptText
,
decryptText
)
decryptText
=
P
KCS7UnPadding
(
decryptText
)
decryptText
=
p
KCS7UnPadding
(
decryptText
)
return
decryptText
,
nil
// gunzip
zbuf
:=
bytes
.
NewBuffer
(
decryptText
)
zrd
,
err
:=
gzip
.
NewReader
(
zbuf
)
if
err
!=
nil
{
return
nil
,
err
}
defer
zrd
.
Close
()
data
,
_
=
ioutil
.
ReadAll
(
zrd
)
return
data
,
nil
}
func
P
KCS7Padding
(
ciphertext
[]
byte
,
blockSize
int
)
[]
byte
{
func
p
KCS7Padding
(
ciphertext
[]
byte
,
blockSize
int
)
[]
byte
{
padding
:=
blockSize
-
len
(
ciphertext
)
%
blockSize
padtext
:=
bytes
.
Repeat
([]
byte
{
byte
(
padding
)},
padding
)
return
append
(
ciphertext
,
padtext
...
)
}
func
P
KCS7UnPadding
(
origData
[]
byte
)
[]
byte
{
func
p
KCS7UnPadding
(
origData
[]
byte
)
[]
byte
{
length
:=
len
(
origData
)
unpadding
:=
int
(
origData
[
length
-
1
])
return
origData
[
:
(
length
-
unpadding
)]
}
func
GetAuthKey
(
str
string
)
(
authKey
string
)
{
md5Ctx
:=
md5
.
New
()
md5Ctx
.
Write
([]
byte
(
str
))
md5Str
:=
md5Ctx
.
Sum
(
nil
)
return
hex
.
EncodeToString
(
md5Str
)
}
src/frp/utils/pcrypto/pcrypto_test.go
浏览文件 @
2ba84d37
...
...
@@ -15,15 +15,14 @@
package
pcrypto
import
(
"crypto/aes"
"fmt"
"testing"
)
func
TestEncrypt
o
(
t
*
testing
.
T
)
{
func
TestEncrypt
(
t
*
testing
.
T
)
{
pp
:=
new
(
Pcrypto
)
pp
.
Init
([]
byte
(
"Hana"
))
res
,
err
:=
pp
.
Encrypt
o
([]
byte
(
"Just One Test!"
))
res
,
err
:=
pp
.
Encrypt
([]
byte
(
"Just One Test!"
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
...
...
@@ -31,31 +30,18 @@ func TestEncrypto(t *testing.T) {
fmt
.
Printf
(
"[%x]
\n
"
,
res
)
}
func
TestDecrypt
o
(
t
*
testing
.
T
)
{
func
TestDecrypt
(
t
*
testing
.
T
)
{
pp
:=
new
(
Pcrypto
)
pp
.
Init
([]
byte
(
"Hana"
))
res
,
err
:=
pp
.
Encrypt
o
([]
byte
(
"Just One Test!"
))
res
,
err
:=
pp
.
Encrypt
([]
byte
(
"Just One Test!"
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
res
,
err
=
pp
.
Decrypt
o
(
res
)
res
,
err
=
pp
.
Decrypt
(
res
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
fmt
.
Printf
(
"[%s]
\n
"
,
string
(
res
))
}
func
TestPKCS7Padding
(
t
*
testing
.
T
)
{
ltt
:=
[]
byte
(
"Test_PKCS7Padding"
)
ltt
=
PKCS7Padding
(
ltt
,
aes
.
BlockSize
)
// fmt.Printf("[%x]\n", (ltt))
}
func
TestPKCS7UnPadding
(
t
*
testing
.
T
)
{
ltt
:=
[]
byte
(
"Test_PKCS7Padding"
)
ltt
=
PKCS7Padding
(
ltt
,
aes
.
BlockSize
)
ltt
=
PKCS7UnPadding
(
ltt
)
// fmt.Printf("[%x]\n", ltt)
}
src/frp/utils/version/version.go
浏览文件 @
2ba84d37
...
...
@@ -19,7 +19,7 @@ import (
"strings"
)
var
version
string
=
"0.
2
.0"
var
version
string
=
"0.
3
.0"
func
Full
()
string
{
return
version
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录