【开源学习】FRP反向代理工具详解
liebian365 2024-10-22 15:40 16 浏览 0 评论
1. What
frp 是一款高性能的反向代理应用,专注于内网穿透。它支持多种协议,包括 TCP、UDP、HTTP、HTTPS 等,并且具备 P2P 通信功能。使用 frp,您可以安全、便捷地将内网服务暴露到公网,通过拥有公网 IP 的节点进行中转。
- 多种协议支持:客户端服务端通信支持 TCP、QUIC、KCP 和 Websocket 等多种协议。
- TCP 连接流式复用:在单个连接上承载多个请求,减少连接建立时间,降低请求延迟。
- 代理组间的负载均衡。
- 端口复用:多个服务可以通过同一个服务端端口暴露。
- P2P 通信:流量不必经过服务器中转,充分利用带宽资源。
- 客户端插件:提供多个原生支持的客户端插件,如静态文件查看、HTTPS/HTTP 协议转换、HTTP、SOCKS5 代理等,以便满足各种需求。
- 服务端插件系统:高度可扩展的服务端插件系统,便于根据自身需求进行功能扩展。
- 用户友好的 UI 页面:提供服务端和客户端的用户界面,使配置和监控变得更加方便。
2. 安装
git clone git@github.com:fatedier/frp.git
cd frp
make
cd frps/
yum install npm
npm install npm-run-all --save-dev
npm i npm-run-all -g
make
npm install
npm audit fix
npm run dev
3. 搭建测试环境
大部分场景可以通过 一台centos7 + docker组网隔离 测试:
RDP协议需要 两台windows 测试:
// 测试的centos7 dockerfile制作
FROM centos7:alirepo
ADD frpDevKit /
WORKDIR /
RUN chmod 777 frps frpc \
&& yum install -y passwd openssl openssh-server openssh-clients \
&& yum install -y iproute iproute-doc initscripts
// Makefile
IMAGE_NAME := centos7-frp
COMPILE_TIME = $(shell date +"%Y%m%d%H%M%S")
image:
docker build -t $(IMAGE_NAME):$(COMPILE_TIME) -t $(IMAGE_NAME):latest .
.PHONY: image
ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
// 模拟访问者内网的主机,比如堡垒机和syslog server
docker network create -d bridge --subnet 10.10.10.0/24 --gateway 10.10.10.1 secpoolZone
docker run -itd --name jumpserver --net=secpoolZone --privileged=true centos7-frp:latest /sbin/init
docker run -itd --name syslogserver --net=secpoolZone --privileged=true centos7-frp:latest /sbin/init
// 模拟被访问者的内网,比如中石油分支1的办公网
docker network create -d bridge --subnet 169.168.10.0/24 --gateway 169.168.10.1 CNCP1
docker run -itd --name CNCP1-host1 --net=CNCP1 --privileged=true centos7-frp:latest /sbin/init
docker run -itd --name CNCP1-host2 --net=CNCP1 --privileged=true centos7-frp:latest /sbin/init
// 模拟被访问者的内网,比如中石油分支2的办公网
docker network create -d bridge --subnet 169.178.10.0/24 --gateway 169.178.10.1 CNCP2
docker run -itd --name CNCP2-host1 --net=CNCP2 --privileged=true centos7-frp:latest /sbin/init
// 模拟被访问者的内网,比如中石化分支1的办公网,并且与中石油分支1的办公网私网ip重叠,采用新建网卡实现
docker network create -d bridge --subnet 169.188.10.0/24 --gateway 169.188.10.1 SINOPEC1
docker run -itd --name SINOPEC1-host1 --net=SINOPEC1 --privileged=true centos7-frp:latest /sbin/init
// 模拟有公网暴露面的FRPS
docker network create -d bridge --subnet 122.245.248.0/24 --gateway 122.245.248.1 publicNet
docker run -itd --name FRPS --net=publicNet --privileged=true centos7-frp:latest /sbin/init
// 模拟多个内网的主机可以通公网
docker network connect publicNet CNCP1-host1
docker network connect publicNet CNCP1-host2
docker network connect publicNet jumpserver
docker network connect publicNet syslogserver
docker network connect publicNet CNCP2-host1
docker network connect publicNet SINOPEC1-host1
// 一些必要的前置操作
ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
systemctl start sshd
passwd root
yum install telnet xinetd telnet-server.x86_64 -y
systemctl start telnet.socket
systemctl start xinetd
// 租户内网重叠场景构造
yum install net-tools -y
ifconfig eth0:0 169.168.10.2 netmask 255.255.255.0 up
// 清理现场
docker stop/rm FRPS CNCP1-host2 CNCP1-host1 syslogserver jumpserver
公网暴露的,代理网关FRPS:
访问者的私网主机,堡垒机和syslog服务器:
中石油分支一,主机1和主机2:
中石油分支二,主机1
中石油分支一,主机1
4. 测试场景
4.1. 堡垒机访问中石油分支1的任意主机
# frps.toml
bindPort = 7000
# CNCP1-host2
serverAddr = "122.245.248.2"
serverPort = 7000
[[proxies]]
name = "CNCP1-host2"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000
# CNCP1-host1
serverAddr = "122.245.248.2"
serverPort = 7000
[[proxies]]
name = "CNCP1-host1"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6001
# 源神启动
./frpc -c ./frpc.toml
./frps -c ./frps.toml
# 登入到jumpserver进行内网主机纳管:
ssh -oPort=6001 root@122.245.248.2
ssh -oPort=6000 root@122.245.248.2
服务端纳管所有proxy:
中石油分支1,host1连上server:
中石油分支1,host2连上server:
登录到jumpserver通过frps代理去访问中石油分支1的主机1和主机2:
4.2. 堡垒机访问中石油分支2的任意主机
# CNCP2-host1
serverAddr = "122.245.248.2"
serverPort = 7000
[[proxies]]
name = "CNCP2-host1"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6003
# 源神启动
./frpc -c ./frpc.toml
# 登入到jumpserver进行内网主机纳管:
ssh -oPort=6003 root@122.245.248.2
proxy注册上来了:
4.3. 堡垒机访问不同租户但内网ip重叠场景
# SINOPEC1-host1
serverAddr = "122.245.248.2"
serverPort = 7000
[[proxies]]
name = "SINOPEC1-host1"
type = "tcp"
localIP = "169.168.10.2"
localPort = 22
remotePort = 6004
# 源神启动
./frpc -c ./frpc.toml
# 登入到jumpserver进行内网主机纳管:
ssh -oPort=6004 root@122.245.248.2
这个私网ip是重叠的:
4.4. RDP,TELNET,FTP协议测试
4.4.1. RDP协议测试
首先,我们需要设置一下被控 PC 端(也就是希望被远程控制的设备)在 frp 的 GitHub 下载页面 中下载对应的执行包,这里因为内网目标被控主机是 Windows 10,因此需要下载 Windows 版本。
解压缩之后,将其中的 frpc.exe 以及 frpc.ini 拷贝到 C:\ftp 这个目录下面,然后使用编辑器对 frpc.ini 文件进行编辑。
frpc.ini 文件中主要分为两个部分,最上面[common]是和云端服务器通信的部分,因此server_addr填写的是对应的云服务器的 ip 地址,而下面这个server_port则是刚才我们在服务端所设置的bind_port,两者需要保持一致。
下面部分是针对需要内网穿透的服务,比如针对 RDP 的代码写法如下:
[RDP]
type = tcp
local_ip = 127.0.0.1
local_port = 3389
remote_port = 7002
完成之后点击保存,接着我们需要对电脑的远程进行设置。右键点击「此电脑」-「属性」,找到「远程设置」,在「远程桌面」中勾选「允许远程连接到此计算机」,同时取消「仅允许运行使用网络级别身份验证的远程桌面的计算机连接」的勾选,然后点击「确定」。
最后,我们需要打开 Windows 防火墙给以上服务予以放行,在控制面板\所有控制面板项\Windows Defender 防火墙\允许的应用中点击「更改设置」,然后在下面找到「远程桌面」和「远程桌面(webSocket)」并分别勾选上「专用」和「公用」。
之后我们打开c:\frp目录,按住键盘上的shift键后右键选择「在此处打开 Powershell 窗口」,执行以下命令来开启 frp 客户端:
.\frpc.exe -c frpc.ini
如果下面的终端输入显示有[RDP] start proxy success 则表示实际上服务已经成功开启,使用控制端的「微软远程桌面」应该就可以实现远程控制了。
接下来我们就可以用控制端的 PC 测试一下,打开「远程桌面连接」,然后在「计算机」这一栏中输入云主机的公网 IP 后映射的端口号,比如我设置的 7002,然后点击连接。
然后在弹出的警告中选择「是」。
4.4.2. TELNET协议测试
# CNCP2-host1
serverAddr = "122.245.248.2"
serverPort = 7000
webServer.addr = "127.0.0.1"
webServer.port = 7400
webServer.user = "admin"
webServer.password = "admin"
[[proxies]]
name = "CNCP2-host1"
type = "tcp"
localIP = "127.0.0.1"
localPort = 23
remotePort = 6003
// 开启telnet服务
yum install telnet xinetd telnet-server.x86_64 -y
systemctl start telnet.socket
systemctl start xinetd
提前要搞个非root用户名,因为telnet不是很安全:
4.4.3. 【不满足,但可以用SFTP】FTP协议测试
4.5. Agent自身状态监控
使用健康检查类型tcp,服务端口将被 ping (TCPing):
# frpc.toml
# frpc.toml
webServer.addr = "127.0.0.1"
webServer.port = 7400
webServer.user = "admin"
webServer.password = "admin"
[[proxies]]
name = "test1"
type = "tcp"
localPort = 22
remotePort = 6000
# Enable TCP health check
healthCheck.type = "tcp"
# TCPing timeout seconds
healthCheck.timeoutSeconds = 3
# If health check failed 3 times in a row, the proxy will be removed from frps
healthCheck.maxFailed = 3
# A health check every 10 seconds
healthCheck.intervalSeconds = 10
对于健康检查类型http,HTTP 请求将发送到服务,并且预期得到 HTTP 2xx OK 响应:
# frpc.toml
[[proxies]]
name = "web"
type = "http"
localIP = "127.0.0.1"
localPort = 80
customDomains = ["test.example.com"]
# Enable HTTP health check
healthCheck.type = "http"
# frpc will send a GET request to '/status'
# and expect an HTTP 2xx OK response
healthCheck.path = "/status"
healthCheck.timeoutSeconds = 3
healthCheck.maxFailed = 3
healthCheck.intervalSeconds = 10
# frps.tmol
# 默认为 127.0.0.1,如果需要公网访问,需要修改为 0.0.0.0。
webServer.addr = "0.0.0.0"
webServer.port = 7500
# dashboard 用户名密码,可选,默认为空
webServer.user = "admin"
webServer.password = "admin"
client测上报的状态:
curl -u admin:admin http://127.0.0.1:7400/api/status
server测收集所有状态:
curl -u admin:admin http://127.0.0.1:7500/api/proxy/tcp
curl -u admin:admin http://127.0.0.1:7500/api/serverinfo
4.6. P2P 2G大文件传输
sftp双向传输大文件,truncate一个大文件发过去:
# CNCP1-host2
serverAddr = "122.245.248.2"
serverPort = 7000
[[proxies]]
name = "p2p_ssh"
type = "xtcp"
# 只有共享密钥 (secretKey) 与服务器端一致的用户才能访问该服务
secretKey = "abcdefg"
localIP = "127.0.0.1"
localPort = 22
[[visitors]]
name = "p2p_ssh_visitor"
type = "xtcp"
# 要访问的 P2P 代理的名称
serverName = "p2p_ssh1"
secretKey = "abcdefg"
# 绑定本地端口以访问 SSH 服务
bindAddr = "127.0.0.1"
bindPort = 6000
# 如果需要自动保持隧道打开,将其设置为 true
keepTunnelOpen = false
# CNCP1-host1
serverAddr = "122.245.248.2"
serverPort = 7000
[[proxies]]
name = "p2p_ssh1"
type = "xtcp"
# 只有共享密钥 (secretKey) 与服务器端一致的用户才能访问该服务
secretKey = "abcdefg"
localIP = "127.0.0.1"
localPort = 22
[[visitors]]
name = "p2p_ssh_visitor"
type = "xtcp"
# 要访问的 P2P 代理的名称
serverName = "p2p_ssh"
secretKey = "abcdefg"
# 绑定本地端口以访问 SSH 服务
bindAddr = "127.0.0.1"
bindPort = 6000
# 如果需要自动保持隧道打开,将其设置为 true
keepTunnelOpen = false
5. 与同类代理工具比对
工具 | 版本号 | TCP延迟 | TCP吞吐 | HTTP延迟 | HTTP吞吐 | 配置复杂度 | 安全性 | 稳定性 | 欢迎度 |
frp | v0.43.0 | 28ms | 3.74MB/s | 105ms | 12.53MB/s | 中 | 中上 | 高 | 最高 |
nps | v0.26.9 | 41ms | 2.15MB/s | 390ms | 3.25MB/s | 最低 | 最低 | 低 | 较低 |
ssh-tunnel | N/A | 19ms | 4.86MB/s | 62ms | 10.23MB/s | 低 | 中下 | 中 | 高 |
gost | v2.11.1 | 15ms | 5.38MB/s | 55ms | 11.87MB/s | 中 | 中 | 中上 | 中 |
vip72 | v2.3.2 | 12ms | 6.12MB/s | 32ms | 15.24MB/s | 最高 | 最高 | 最高 | 较低 |
v2ray | v4.37.1 | 10ms | 6.83MB/s | 27ms | 16.93MB/s | 高 | 最高 | 高 | 高 |
NeutrinoProxy | v1.8.0 | 23ms | 5.12MB/s | 67ms | 12.47MB/s | 中 | 中 | 中 | 中 |
ngrok | v1.7.1 | 35ms | 2.74MB/s | 125ms | 10.28MB/s | 最低 | 低 | 高 | 高 |
我搂一眼v2ray的内网穿透配置,有这功夫strongswan也能跑起来了:
{
"reverse":{
// 这是 A 的反向代理设置,必须有下面的 bridges 对象
"bridges":[
{
"tag":"bridge", // 关于 A 的反向代理标签,在路由中会用到
"domain":"private.cloud.com" // A 和 B 反向代理通信的域名,可以自己取一个,可以不是自己购买的域名,但必须跟下面 B 中的 reverse 配置的域名一致
}
]
},
"outbounds":[
{
//A连接B的outbound
"tag":"tunnel", // A 连接 B的 outbound 的标签,在路由中会用到
"protocol":"vmess",
"settings":{
"vnext":[
{
"address":"serveraddr.com", // B 地址,IP 或 实际的域名
"port":16823,
"users":[
{
"id":"b831381d-6324-4d53-ad4f-8cda48b30811",
"alterId":64
}
]
}
]
}
},
// 另一个 outbound,最终连接私有网盘
{
"protocol":"freedom",
"settings":{
},
"tag":"out"
}
],
"routing":{
"rules":[
{
// 配置 A 主动连接 B 的路由规则
"type":"field",
"inboundTag":[
"bridge"
],
"domain":[
"full:private.cloud.com"
],
"outboundTag":"tunnel"
},
{
// 反向连接访问私有网盘的规则
"type":"field",
"inboundTag":[
"bridge"
],
"outboundTag":"out"
}
]
}
}
{
"reverse":{ //这是 B 的反向代理设置,必须有下面的 portals 对象
"portals":[
{
"tag":"portal",
"domain":"private.cloud.com" // 必须和上面 A 设定的域名一样
}
]
},
"inbounds":[
{
// 接受 C 的inbound
"tag":"tunnel", // 标签,路由中用到
"port":11872,
"protocol":"vmess",
"settings":{
"clients":[
{
"id":"a26efdb8-ef34-4278-a4e6-2af32cc010aa",
"alterId":64
}
]
}
},
// 另一个 inbound,接受 A 主动发起的请求
{
"tag": "interconn",// 标签,路由中用到
"port":16823,
"protocol":"vmess",
"settings":{
"clients":[
{
"id":"b831381d-6324-4d53-ad4f-8cda48b30811",
"alterId":64
}
]
}
}
],
"routing":{
"rules":[
{ //路由规则,接收 C 的请求后发给 A
"type":"field",
"inboundTag":[
"external"
],
"outboundTag":"portal"
},
{ //路由规则,让 B 能够识别这是 A 主动发起的反向代理连接
"type":"field",
"inboundTag":[
"tunnel"
],
"domain":[
"full:private.cloud.com"
],
"outboundTag":"portal"
}
]
}
}
Reference
https://github.com/fatedier/frp/blob/dev/README_zh.md
https://cloud.tencent.com/developer/article/1837482
https://juejin.cn/post/7042486792011907086
https://doc.itopcms.com/docs/go-project/go-project-1e54jq1c088tb
https://docs.jumpserver.org/zh/v3/architecture/#3
https://github.com/fatedier/frp?tab=readme-ov-file#prometheus
https://blog.csdn.net/qq_46490950/article/details/118978635
https://blog.51cto.com/chengdumeiyouni/2815244
https://blog.csdn.net/a20251839/article/details/113871215
https://alianga.com/articles/nas-contrast
https://jiajunhuang.com/articles/2019_06_11-frpc_source_code_part1.md.html
https://sspai.com/post/60852
相关推荐
- 4万多吨豪华游轮遇险 竟是因为这个原因……
-
(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...
- “菜鸟黑客”必用兵器之“渗透测试篇二”
-
"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...
- 科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白
-
作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...
- 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势
-
作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...
- 知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势
-
智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...
- 每日新闻播报(September 14)_每日新闻播报英文
-
AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...
- 香港新巴城巴开放实时到站数据 供科技界研发使用
-
中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...
- 5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper
-
本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...
- Qt动画效果展示_qt显示图片
-
今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...
- 如何从0到1设计实现一门自己的脚本语言
-
作者:dong...
- 三年级语文上册 仿写句子 需要的直接下载打印吧
-
描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...
- C++|那些一看就很简洁、优雅、经典的小代码段
-
目录0等概率随机洗牌:1大小写转换2字符串复制...
- 二年级上册语文必考句子仿写,家长打印,孩子照着练
-
二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)