FRP进行端口转发访问web服务
利用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);
}
在远程请求时会返回:
局域网内白名单外:
本地或者白名单内: