Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

服务端如何优雅地控制客户端的连接 #4326

Closed
1 of 11 tasks
Developer024 opened this issue Jul 9, 2024 · 17 comments
Closed
1 of 11 tasks

服务端如何优雅地控制客户端的连接 #4326

Developer024 opened this issue Jul 9, 2024 · 17 comments

Comments

@Developer024
Copy link

Describe the feature request

业务场景: 每个分发的客户端都限制了流量,如果某个客户端的流量达到了设置的阈值则应该断开服务端的连接。

当前想到几种解决方式,但是都有缺陷。请问各位还有更好的方法吗?

使用心跳包处理 (目前在用)

使用 RPC 的 Ping 接口收到客户端发送的心跳包进行流量鉴权处理。这种做法虽然可以实现业务需求,但是
客户端可以自行修改配置文件,控制ping的频率,如果客户端把心跳频率设置到1s,则后端鉴权压力过大。
不希望把这个权限下放到客户端,但是那几个rpc接口好像都不会上传心跳包的设置,也就无法做到服务端下发修改覆盖。

另外,如果使用了tcp_mux_keepalive_interval 功能,则Ping接口则不会收到心跳数据。

使用连接数进行处理 (不优雅)

使用 NewUserConn 接口进行流量鉴权处理。把客户端的每一条连接数都进行鉴权,但如果客户端的连接数特别高,或遭遇CC攻击,那对后端的处理也是毁灭型的破坏。

请问还有什么方式可以做到这个场景的需求吗?

Describe alternatives you've considered

No response

Affected area

  • Docs
  • Installation
  • Performance and Scalability
  • Security
  • User Experience
  • Test and Release
  • Developer Infrastructure
  • Client Plugin
  • Server Plugin
  • Extensions
  • Others
@fatedier
Copy link
Owner

fatedier commented Jul 9, 2024

目前还没有这方面的开发计划。

@adminxy
Copy link

adminxy commented Jul 10, 2024

感谢大佬的回复和解决方案,我会持续关注这个issues ,有好的办法和思路我也会及时在本issues下反馈分享

@adminxy
Copy link

adminxy commented Jul 10, 2024

我之前准备的实现思路是,每天定时吧frps重启,强制所有客户端重新链接,进行校验,但是这样会对其他客户端/用户,的体验不是很好

@adminxy
Copy link

adminxy commented Jul 10, 2024

然后还有一个思路
是从这个插件【frps-auth】 看到的 仓库地址:https://github.com/chi-cat/frps-auth
image
这个插件的作者实现思路,是修改了frps的源码,提供了结束代理方法

在您回复之前,我也打算尝试修改frps源码实现这一功能,但是无奈我不太会go语言,但是我也在尝试自己修改,如果可以的话,我会开源一个 会长期维护,并且包含关闭指定代理的 方法或api 的版本 ,

当然,如果有大佬愿意修改并开源,那就更好了

@adminxy
Copy link

adminxy commented Jul 10, 2024

目前还没有这方面的开发计划。

我在 插件《 frps-auth 仓库地址:https://github.com/chi-cat/frps-auth 》 注意到这样一句话,

frps-aut作者有提到: #4326 (comment) (截屏标注位置)
【根据和frp作者大大沟通;在frp的dev分支上已经加入了类似的api,此功能可能会在dev合并到master分支后发生更改。】

想问一下您,现在frp中, 有这个api么,有的话有相关说明文档吗

@Developer024
Copy link
Author

我之前准备的实现思路是,每天定时吧frps重启,强制所有客户端重新链接,进行校验,但是这样会对其他客户端/用户,的体验不是很好

Ping接口的心跳包是可以做实时校验的。正如此Issue描述的那样。使用 服务端RPC接口的 Ping 即可。

但是此Issue引伸出了另外一个问题,如果把心跳包的权限给客户端, 由客户端决定心跳频率并不是很好。

@adminxy
Copy link

adminxy commented Jul 10, 2024

我之前准备的实现思路是,每天定时吧frps重启,强制所有客户端重新链接,进行校验,但是这样会对其他客户端/用户,的体验不是很好

Ping接口的心跳包是可以做实时校验的。正如此Issue描述的那样。使用 服务端RPC接口的 Ping 即可。

但是此Issue引伸出了另外一个问题,如果把心跳包的权限给客户端, 由客户端决定心跳频率并不是很好。

确实是有这个问题,如果使用Ping、NewUserConn的话,不是和优雅,

特别是ping 会使服务器变得很被动,而且会给服务器造成很大的压力,

我感觉最优雅的处理办法还是 【修改了frps的源码,提供了结束代理 方法、api(可以限制一下,只能本机调用)】

但是无奈go,我并不熟练,但是我目前也在看frp的源代码了

@Developer024
Copy link
Author

我之前准备的实现思路是,每天定时吧frps重启,强制所有客户端重新链接,进行校验,但是这样会对其他客户端/用户,的体验不是很好

Ping接口的心跳包是可以做实时校验的。正如此Issue描述的那样。使用 服务端RPC接口的 Ping 即可。
但是此Issue引伸出了另外一个问题,如果把心跳包的权限给客户端, 由客户端决定心跳频率并不是很好。

确实是有这个问题,如果使用Ping、NewUserConn的话,不是和优雅,

特别是ping 会使服务器变得很被动,而且会给服务器造成很大的压力,

我感觉最优雅的处理办法还是 【修改了frps的源码,提供了结束代理 方法、api(可以限制一下,只能本机调用)】

但是无奈go,我并不熟练,但是我目前也在看frp的源代码了

是的,较优解当然是可以提供一个由服务端主动关闭连接的api。

不过如果想工作量小一点的话,我想是增强 NewProxy 这个RPC接口,可以上报客户端的心跳配置,再由鉴权服务器进行修改下发,从服务端就可以控制客户端的上报频次。

@adminxy
Copy link

adminxy commented Jul 10, 2024

我之前准备的实现思路是,每天定时吧frps重启,强制所有客户端重新链接,进行校验,但是这样会对其他客户端/用户,的体验不是很好

Ping接口的心跳包是可以做实时校验的。正如此Issue描述的那样。使用 服务端RPC接口的 Ping 即可。
但是此Issue引伸出了另外一个问题,如果把心跳包的权限给客户端, 由客户端决定心跳频率并不是很好。

确实是有这个问题,如果使用Ping、NewUserConn的话,不是和优雅,
特别是ping 会使服务器变得很被动,而且会给服务器造成很大的压力,
我感觉最优雅的处理办法还是 【修改了frps的源码,提供了结束代理 方法、api(可以限制一下,只能本机调用)】
但是无奈go,我并不熟练,但是我目前也在看frp的源代码了

是的,较优解当然是可以提供一个由服务端主动关闭连接的api。

不过如果想工作量小一点的话,我想是增强 NewProxy 这个RPC接口,可以上报客户端的心跳配置,再由鉴权服务器进行修改下发,从服务端就可以控制客户端的上报频次。

这样确实也可以

强制客户端设置心跳在合理范围内,就允许创建这个代理,

但是这个也要涉及到改动frp代码。原版的frp是不支持这个功能的

当然这个要比做一个关闭代理api简单,

但是你这个 【 增强 NewProxy 】的方案 这个我突然想到了几个问题:

1.客户端 必须使用修改过配套的frpc,这对于用户来说不是很友好,而且有的设备比如软路由,他的frpc一般是系统内置的,更换起来并不方便。

2.假如我的客户端是经过我修改的,我的frpc,创建代理的时候的时候,请求参数里面的心跳时间直接设置成任意的,但是其实我的frpc客户端是不发送心跳的

@Developer024
Copy link
Author

1.客户端 必须使用修改过配套的frpc,这对于用户来说不是很友好,而且有的设备比如软路由,他的frpc一般是系统内置的,更换起来并不方便。

2.假如我的客户端是经过我修改的,我的frpc,创建代理的时候的时候,请求参数里面的心跳时间直接设置成任意的,但是其实我的frpc客户端是不发送心跳的

这个得看源码怎么实现的了,我这一部分功能我还没去看过。

RPC接口是有替换能力的,直接从服务端拦截下发覆盖即可 文档引用

等有时间我看看提个pr

@adminxy
Copy link

adminxy commented Jul 11, 2024

1.客户端 必须使用修改过配套的frpc,这对于用户来说不是很友好,而且有的设备比如软路由,他的frpc一般是系统内置的,更换起来并不方便。
2.假如我的客户端是经过我修改的,我的frpc,创建代理的时候的时候,请求参数里面的心跳时间直接设置成任意的,但是其实我的frpc客户端是不发送心跳的

这个得看源码怎么实现的了,我这一部分功能我还没去看过。

RPC接口是有替换能力的,直接从服务端拦截下发覆盖即可 文档引用

等有时间我看看提个pr

我等测试一下这个的效果,如果服务器可以直接拦截覆盖,这样看起来就没多大的问题了,我有时间测试一下,效果如何

@adminxy
Copy link

adminxy commented Jul 12, 2024

1.客户端 必须使用修改过配套的frpc,这对于用户来说不是很友好,而且有的设备比如软路由,他的frpc一般是系统内置的,更换起来并不方便。
2.假如我的客户端是经过我修改的,我的frpc,创建代理的时候的时候,请求参数里面的心跳时间直接设置成任意的,但是其实我的frpc客户端是不发送心跳的

这个得看源码怎么实现的了,我这一部分功能我还没去看过。

RPC接口是有替换能力的,直接从服务端拦截下发覆盖即可 文档引用

等有时间我看看提个pr

我在【 https://gofrp.org/zh-cn/docs/features/common/server-plugin/#%E6%8E%A5%E5%8F%A3 】里面并没有找到,那个RPC 请求请求,会携带客户端的心跳时间配置,以及如何修改返回客户端配置

如果可以的话,方便提供一个示例么

@Developer024
Copy link
Author

1.客户端 必须使用修改过配套的frpc,这对于用户来说不是很友好,而且有的设备比如软路由,他的frpc一般是系统内置的,更换起来并不方便。
2.假如我的客户端是经过我修改的,我的frpc,创建代理的时候的时候,请求参数里面的心跳时间直接设置成任意的,但是其实我的frpc客户端是不发送心跳的

这个得看源码怎么实现的了,我这一部分功能我还没去看过。
RPC接口是有替换能力的,直接从服务端拦截下发覆盖即可 文档引用
等有时间我看看提个pr

我在【 https://gofrp.org/zh-cn/docs/features/common/server-plugin/#%E6%8E%A5%E5%8F%A3 】里面并没有找到,那个RPC 请求请求,会携带客户端的心跳时间配置,以及如何修改返回客户端配置

如果可以的话,方便提供一个示例么

你的问题,正如此issue最开始的描述。但是那几个rpc接口好像都不会上传心跳包的设置,也就无法做到服务端下发修改覆盖。
如果需要携带此参数需要修改源码提交pr,这是我认为完成需求最简便的方法。

关于您说的 如何修改返回客户端配置, 请查看文档中关于RPC返回替换部分描述。

允许且需要替换操作内容

{
    "unchange": false,
    "content": {
        ... // 替换后的操作信息,格式必须和请求时的一致
    }
}

@adminxy
Copy link

adminxy commented Jul 12, 2024

1.客户端 必须使用修改过配套的frpc,这对于用户来说不是很友好,而且有的设备比如软路由,他的frpc一般是系统内置的,更换起来并不方便。
2.假如我的客户端是经过我修改的,我的frpc,创建代理的时候的时候,请求参数里面的心跳时间直接设置成任意的,但是其实我的frpc客户端是不发送心跳的

这个得看源码怎么实现的了,我这一部分功能我还没去看过。
RPC接口是有替换能力的,直接从服务端拦截下发覆盖即可 文档引用
等有时间我看看提个pr

我在【 https://gofrp.org/zh-cn/docs/features/common/server-plugin/#%E6%8E%A5%E5%8F%A3 】里面并没有找到,那个RPC 请求请求,会携带客户端的心跳时间配置,以及如何修改返回客户端配置
如果可以的话,方便提供一个示例么

你的问题,正如此issue最开始的描述。但是那几个rpc接口好像都不会上传心跳包的设置,也就无法做到服务端下发修改覆盖。 如果需要携带此参数需要修改源码提交pr,这是我认为完成需求最简便的方法。

关于您说的 如何修改返回客户端配置, 请查看文档中关于RPC返回替换部分描述。

允许且需要替换操作内容

{
    "unchange": false,
    "content": {
        ... // 替换后的操作信息,格式必须和请求时的一致
    }
}

比如我要把心跳包设置为10 您看这样对吗
{
"unchange": False,
"content": {'user': {'user': 'fake',"transport.heartbeatInterval ":"10", 'metas': {'token': 'fake', 'version': '1.0.0'}, 'run_id': '705bc8dfd7d73481'}}
}

我这样设置客户端似乎并没有生效,您看下是不是哪里不对

@Developer024
Copy link
Author

1.客户端 必须使用修改过配套的frpc,这对于用户来说不是很友好,而且有的设备比如软路由,他的frpc一般是系统内置的,更换起来并不方便。
2.假如我的客户端是经过我修改的,我的frpc,创建代理的时候的时候,请求参数里面的心跳时间直接设置成任意的,但是其实我的frpc客户端是不发送心跳的

这个得看源码怎么实现的了,我这一部分功能我还没去看过。
RPC接口是有替换能力的,直接从服务端拦截下发覆盖即可 文档引用
等有时间我看看提个pr

我在【 https://gofrp.org/zh-cn/docs/features/common/server-plugin/#%E6%8E%A5%E5%8F%A3 】里面并没有找到,那个RPC 请求请求,会携带客户端的心跳时间配置,以及如何修改返回客户端配置
如果可以的话,方便提供一个示例么

你的问题,正如此issue最开始的描述。但是那几个rpc接口好像都不会上传心跳包的设置,也就无法做到服务端下发修改覆盖。 如果需要携带此参数需要修改源码提交pr,这是我认为完成需求最简便的方法。
关于您说的 如何修改返回客户端配置, 请查看文档中关于RPC返回替换部分描述。

允许且需要替换操作内容

{
    "unchange": false,
    "content": {
        ... // 替换后的操作信息,格式必须和请求时的一致
    }
}

比如我要把心跳包设置为10 您看这样对吗 { "unchange": False, "content": {'user': {'user': 'fake',"transport.heartbeatInterval ":"10", 'metas': {'token': 'fake', 'version': '1.0.0'}, 'run_id': '705bc8dfd7d73481'}} }

我这样设置客户端似乎并没有生效,您看下是不是哪里不对

请仔细看此issue提供的问题以及刚才给你回复的comment,其中有提到

        ... // 替换后的操作信息,格式必须和请求时的一致

现在的问题是 客户端都没有上报这个参数,你直接进行下发自然不会生效。

@adminxy
Copy link

adminxy commented Jul 12, 2024

1.客户端 必须使用修改过配套的frpc,这对于用户来说不是很友好,而且有的设备比如软路由,他的frpc一般是系统内置的,更换起来并不方便。
2.假如我的客户端是经过我修改的,我的frpc,创建代理的时候的时候,请求参数里面的心跳时间直接设置成任意的,但是其实我的frpc客户端是不发送心跳的

这个得看源码怎么实现的了,我这一部分功能我还没去看过。
RPC接口是有替换能力的,直接从服务端拦截下发覆盖即可 文档引用
等有时间我看看提个pr

我在【 https://gofrp.org/zh-cn/docs/features/common/server-plugin/#%E6%8E%A5%E5%8F%A3 】里面并没有找到,那个RPC 请求请求,会携带客户端的心跳时间配置,以及如何修改返回客户端配置
如果可以的话,方便提供一个示例么

你的问题,正如此issue最开始的描述。但是那几个rpc接口好像都不会上传心跳包的设置,也就无法做到服务端下发修改覆盖。 如果需要携带此参数需要修改源码提交pr,这是我认为完成需求最简便的方法。
关于您说的 如何修改返回客户端配置, 请查看文档中关于RPC返回替换部分描述。

允许且需要替换操作内容

{
    "unchange": false,
    "content": {
        ... // 替换后的操作信息,格式必须和请求时的一致
    }
}

比如我要把心跳包设置为10 您看这样对吗 { "unchange": False, "content": {'user': {'user': 'fake',"transport.heartbeatInterval ":"10", 'metas': {'token': 'fake', 'version': '1.0.0'}, 'run_id': '705bc8dfd7d73481'}} }
我这样设置客户端似乎并没有生效,您看下是不是哪里不对

请仔细看此issue提供的问题以及刚才给你回复的comment,其中有提到

        ... // 替换后的操作信息,格式必须和请求时的一致

现在的问题是 客户端都没有上报这个参数,你直接进行下发自然不会生效。

好的,了解了,我以为是客户端有上报呢,感谢大佬

@lmxslpc
Copy link

lmxslpc commented Jul 15, 2024

NPS不就是服务端控制的么

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants