百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

【开源学习】FRP反向代理工具详解

liebian365 2024-10-22 15:40 20 浏览 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

相关推荐

go语言也可以做gui,go-fltk让你做出c++级别的桌面应用

大家都知道go语言生态并没有什么好的gui开发框架,“能用”的一个手就能数的清,好用的就更是少之又少。今天为大家推荐一个go的gui库go-fltk。它是通过cgo调用了c++的fltk库,性能非常高...

旧电脑的首选系统:TinyCore!体积小+精简+速度极快,你敢安装吗

这几天老毛桃整理了几个微型Linux发行版,准备分享给大家。要知道可供我们日常使用的Linux发行版有很多,但其中的一些发行版经常会被大家忽视。其实这些微型Linux发行版是一种非常强大的创新:在一台...

codeblocks和VS2019下的fltk使用中文

在fltk中用中文有点问题。英文是这样。中文就成这个样子了。我查了查资料,说用UTF-8编码就行了。edit->Fileencoding->UTF-8然后保存文件。看下下边的编码指示确...

FLTK(Fast Light Toolkit)一个轻量级的跨平台Python GUI库

FLTK(FastLightToolkit)是一个轻量级的跨平台GUI库,特别适用于开发需要快速、高效且简单界面的应用程序。本文将介绍Python中的FLTK库,包括其特性、应用场景以及如何通过代...

中科院开源 RISC-V 处理器“香山”流片,已成功运行 Linux

IT之家1月29日消息,去年6月份,中科院大学教授、中科院计算所研究员包云岗,发布了开源高性能RISC-V处理器核心——香山。近日,包云岗在社交平台晒出图片,香山芯片已流片,回片后...

Linux 5.13内核有望合并对苹果M1处理器支持的初步代码

预计Linux5.13将初步支持苹果SiliconM1处理器,不过完整的支持工作可能还需要几年时间才能完全完成。虽然Linux已经可以在苹果SiliconM1上运行,但这需要通过一系列的补丁才能...

Ubuntu系统下COM口测试教程(ubuntu port)

1、在待测试的板上下载minicom,下载minicom有两种方法:方法一:在Ubuntu软件中心里面搜索下载方法二:按“Ctrl+Alt+T”打开终端,打开终端后输入“sudosu”回车;在下...

湖北嵌入式软件工程师培训怎么选,让自己脱颖而出

很多年轻人毕业即失业、面试总是不如意、薪酬不满意、在家躺平。“就业难”该如何应对,参加培训是否能改变自己的职业走向,在湖北,有哪些嵌入式软件工程师培训怎么选值得推荐?粤嵌科技在嵌入式培训领域有十几年经...

新阁上位机开发---10年工程师的Modbus总结

前言我算了一下,今年是我跟Modbus相识的第10年,从最开始的简单应用到协议了解,从协议开发到协议讲解,这个陪伴了10年的协议,它一直没变,变的只是我对它的理解和认识。我一直认为Modbus协议的存...

创建你的第一个可运行的嵌入式Linux系统-5

@ZHangZMo在MicrochipBuildroot中配置QT5选择Graphic配置文件增加QT5的配置修改根文件系统支持QT5修改output/target/etc/profile配置文件...

如何在Linux下给zigbee CC2530实现上位机

0、前言网友提问如下:粉丝提问项目框架汇总下这个网友的问题,其实就是实现一个网关程序,内容分为几块:下位机,通过串口与上位机相连;下位机要能够接收上位机下发的命令,并解析这些命令;下位机能够根据这些命...

Python实现串口助手 - 03串口功能实现

 串口调试助手是最核心的当然是串口数据收发与显示的功能,pzh-py-com借助的是pySerial库实现串口收发功能,今天痞子衡为大家介绍pySerial是如何在pzh-py-com发挥功能的。一、...

为什么选择UART(串口)作为调试接口,而不是I2C、SPI等其他接口

UART(通用异步收发传输器)通常被选作调试接口有以下几个原因:简单性:协议简单:UART的协议非常简单,只需设置波特率、数据位、停止位和校验位就可以进行通信。相比之下,I2C和SPI需要处理更多的通...

同一个类,不同代码,Qt 串口类QSerialPort 与各种外设通讯处理

串口通讯在各种外设通讯中是常见接口,因为各种嵌入式CPU中串口标配,工业控制中如果不够还通过各种串口芯片进行扩展。比如spi接口的W25Q128FV.对于软件而言,因为驱动接口固定,软件也相对好写,因...

嵌入式linux为什么可以通过PC上的串口去执行命令?

1、uboot(负责初始化基本硬bai件,如串口,网卡,usb口等,然du后引导系统zhi运行)2、linux系统(真正的操作系统)3、你的应用程序(基于操作系统的软件应用)当你开发板上电时,u...

取消回复欢迎 发表评论: