利用Frp進行端口轉發詳細操作
服務器部署Frps
下載運行
- 下載frp可執行包
wget https://github.com/fatedier/frp/releases/download/v0.32.0/frp_0.32.0_linux_amd64.tar.gz
- 解壓
tar zxf frp_0.32.0_linux_amd64.tar.gz
- 進入文件
cd frp_0.32.0_linux_amd64/
- 修改配置文件frps.ini為如下內容
[common]
# frps與frpc通訊的端口
bind_port = 7000
# http請求監聽的端口
vhost_http_port = 8888
# dashboard的用戶名密碼以及端口
dashboard_port = 7500
dashboard_user = admin
dashboard_pwd = 123456
# XXX.com,和*.XXX.com都必須可以解析到本服務器IP
subdomain_host = XXX.com
- 啟動
./frps -c frps.ini
開機自啟服務
- 創建后台啟動模版
vi /etc/systemd/system/frp.service
- frp.service內容如下:
[Unit]
Description=frps
After=network.target
[Service]
ExecStart=/root/frp_0.32.0_linux_amd64/frps -c /root/frp_0.32.0_linux_amd64/frps.ini
[Install]
WantedBy=multi-user.target
- 啟動測試
systemctl start frp.service
- 查看啟動狀態
systemctl status frp.service
- 開機自啟
systemctl enable frp.service
客戶端(采集端工控機)部署Frpc
下載運行
從https://github.com/fatedier/frp/releases下載windows版本包frp_0.32.0_windows_amd64.zip
- 修改Frpc.ini如下
[common]
#服務器IP,域名也可以
server_addr = 123.45.67.89
server_port = 7000
[Test1]
type = http
local_port = 12345
# 二級域名名稱
subdomain = test1
# 使用壓縮
use_compression = true
[Test2]
type = http
local_port = 12346
subdomain = test2
use_compression = true
- 在Frpc.exe所在文件夾,cmd進入命令行
frpc -c .\frpc.ini
出現start proxy success
就表示已經連接成功,此時任何發往http://test1.XXX.com:8888
的請求會轉發至12345
端口,http://test2.XXX.com:8888
的請求會發往12346
端口
采集端區分請求來源
請求分類
-
來自端口轉發的請求
Frp轉發Http請求時,會在headers中加入一個header:
X-Forwarded-For
,值就是該請求來源的真實IP -
局域網內的請求
此類請求可直接從HttpContext中獲取IP
-
本地請求
此類請求的IP為
127.0.0.1
,localhost
,::1
過濾器
設計一個過濾器,為涉及到修改的Action打上過濾IP的標簽.具體邏輯如下:
-
先設計一張IP白名單
-
判斷headers中有沒有
X-Forwarded-For
,有的話直接攔截. -
判斷IP在不在白名單內,不在白名單內直接攔截.
過濾器代碼如下:
public class HttpRequestIPFilterAttribute : ActionFilterAttribute
{
private ILogger logger;
private readonly SystemService systemService;
public HttpRequestIPFilterAttribute(ILogger<HttpRequestIPFilterAttribute> logger, SystemService systemService)
{
this.logger = logger;
this.systemService = systemService;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
var headers = context.HttpContext.Request.Headers;
if (headers.ContainsKey("X-Forwarded-For"))
{
//請求來自端口轉發
logger.LogWarning("檢測到遠程IP的訪問,IP地址:{0}", headers["X-Forwarded-For"]);
var rspmsg = new RspMsg<string>
{
Code = 401,
Msg = "遠程請求無法調用此方法",
Data = null,
};
context.Result = new OkObjectResult(rspmsg);
return;
}
else
{
//請求不是轉發來的
var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
var isWhite=systemService.WhiteIPList.Contains(remoteIp.ToString());
if (!isWhite)
{
logger.LogWarning("檢測到白名單外的IP訪問,IP地址:{0}", remoteIp.ToString());
var rspmsg = new RspMsg<string>
{
Code = 401,
Msg = "非白名單內的IP無法調用此方法",
Data = null,
};
context.Result = new OkObjectResult(rspmsg);
return;
}
}
}
注冊過濾器:
services.AddScoped<HttpRequestIPFilterAttribute>();
在action中使用過濾器
/// <summary>
/// 獲取所有報警項目
/// </summary>
/// <returns></returns>
[HttpGet("v1")]
[ServiceFilter(typeof(HttpRequestIPFilterAttribute))] //使用過濾器
public RspMsg<IEnumerable<AlarmItem>> GetAll()
{
var alarmItems = alarmService.GetAllItems();
return RspMsg<IEnumerable<AlarmItem>>.Success(alarmItems);
}
在遠程請求時會返回:
局域網內白名單外:

本地或者白名單內: