REALITY icon indicating copy to clipboard operation
REALITY copied to clipboard

feat: Add rate limiting to fallback handling via token bucket

Open Meo597 opened this issue 9 months ago • 2 comments

如题,fallback时限速,不影响正常reality

比自己搭nginx过滤SNI的方案更好,更简单

仅demo因此速率写死,欢迎PR我再弄config


对于reality最佳实践虽然是偷同ASN,但考虑到实际情况,大多还是找个知名网站莽就完事了 即便target现在不是CF,可能以后也会用CF等CDN

自己搭nginx限SNI对小白来说不友好,因为需要探测出目标站的所有SNI并放行,哪天target证书更新可能又有新的域 我都嫌费劲,而且流量从nginx绕了一下,感觉怪怪的

此PR使能所有reality握手失败的分别针对上下行限速,允许brust 达成效果:调大after并严格限制rate和brust,使能勉强可开个正常网页应付探测,但想把小鸡拿来中转白嫖流量基本可杜绝

效果图 image

Meo597 avatar Mar 26 '25 00:03 Meo597

https://github.com/XTLS/Xray-core/pull/4550#issuecomment-2754263456

RPRX avatar Mar 26 '25 12:03 RPRX

我想了一下先设计得简单点吧,只给 fallback 下行限速即可,而且看描述 burst 和 after 有点重复,不过 burst 实际上是 capacity?

~~还有你 burst 拼成了 brust,这要是我没仔细看就很搞笑了~~

RPRX avatar Jun 08 '25 05:06 RPRX

我当时考虑的是上行不限,香港优选节点可能被拿来跑直播之类的啥用途。 不过删就删随你,我个人觉得是放在那里,用户用不用看他自己

现在上行的删不删?

after的作用主要是为了防止探测, 因为考虑到如果用户想要突发小一点。那就搞得限速特征很明显,after此时能很好的解决问题 限速三参数是参考nginx做的

~奶子的问题我现在改~

Meo597 avatar Jun 08 '25 05:06 Meo597

我在想怎么设计,请保持在线,~~这样我就不用自己改代码了~~

RPRX avatar Jun 08 '25 05:06 RPRX

我在想怎么设计,请保持在线,~这样我就不用自己改代码了~

ok

Meo597 avatar Jun 08 '25 05:06 Meo597

burst 你这个描述应该改成“突发倍数”更合适吧,且 0 应该默认相当于 1

RPRX avatar Jun 08 '25 05:06 RPRX

~~还有,其实我想搞个范围机制,不过感觉又复杂了~~

RPRX avatar Jun 08 '25 05:06 RPRX

burst本质就是个令牌桶的容量 rate是装令牌的速率

after是单独加的,消耗完了开始用桶算法

nginx是这么干的

Meo597 avatar Jun 08 '25 05:06 Meo597

看明白一些了,令牌数就是 byte

RPRX avatar Jun 08 '25 05:06 RPRX

yes

Meo597 avatar Jun 08 '25 05:06 Meo597

下列六个 limit**** 为选填,可对回落的 REALITY 连接限速。默认为 0 即不启用。

原理:当传输了after减去burst字节后开启限速算法。 限速采用令牌桶算法,桶的容量是burst,每传输一个字节用掉一个token,初始burst是满的。 每秒以rate个token填充桶,直到容量满。

举例:after=10485760, burst=5242880, rate=1048576 代表传输10mb后开始限速为1mb/s,如果暂停传输,5秒后能突发到5mb/s,然后又恢复到1mb/s

建议:过大的afterburst将起不到限速效果,过小的rateburst则十分容易被探测。 应结合被偷网站的资源大小合理设置参数,如果不允许突发,可以把burst设为和rate一样。

Meo597 avatar Jun 08 '25 05:06 Meo597

可以保留上行限速,参数设计成这样:

"limitFallbackUpload": {
    "afterBytes": 0,
    "bytesPerSec": 0,
    "burstBytesPerSec": 0
}

"burstBytesPerSec" 小于 "bytesPerSec" 时自动等于它

RPRX avatar Jun 08 '25 06:06 RPRX

话说 Nginx 没有 "afterSeconds" 这种东西吗

RPRX avatar Jun 08 '25 06:06 RPRX

~~还有虽然单连接上行被限速了,但 XHTTP 上行分包可破此局~~

RPRX avatar Jun 08 '25 06:06 RPRX

话说 Nginx 没有 "afterSeconds" 这种东西吗

我刚翻了下文档nginx的确没有按时间限速的 可以限ip并发连接数,然后每个连接限速

~还有虽然单连接上行被限速了,但 XHTTP 上行分包可破此局~

下个PR按IP限连接数?

Meo597 avatar Jun 08 '25 06:06 Meo597

总之先按我说的参数格式改一下吧

RPRX avatar Jun 08 '25 06:06 RPRX

总之先按我说的参数格式改一下吧

ok

Meo597 avatar Jun 08 '25 06:06 Meo597

你这改的是个啥?完全没按我说的格式,README 也是不该动的地方都动了,还是放下个版本吧

RPRX avatar Jun 08 '25 08:06 RPRX

RatelimitedConn 的 Read() 有个问题,如果数据量大要等很久,或者直接卡死

应该改成 Write() 里有多少 token 就 write 多少数据

RPRX avatar Jun 08 '25 09:06 RPRX

"AfterBytes" 放结构体最上面,LimitFallback struct 放 Config struct 上面,BurstBytesPerSec 小于 BytesPerSec 时直接等于它

RPRX avatar Jun 08 '25 09:06 RPRX

BytesPerSec 改为 int64 吧,不需要它是小数

BurstBytesPerSec 小于 BytesPerSec 时直接等于它

这个还是没改

RPRX avatar Jun 08 '25 10:06 RPRX

这样吧,三个参数全改成 uint64

判断是否启用只需判断 config.LimitFallbackUpload.BytesPerSec 是否为 0

RPRX avatar Jun 08 '25 10:06 RPRX

after是可能为负数的

Meo597 avatar Jun 08 '25 10:06 Meo597

after是可能为负数的

意义是?

RPRX avatar Jun 08 '25 10:06 RPRX

不是设置的值,运行中计算的时候可能为负

Meo597 avatar Jun 08 '25 10:06 Meo597

只有参数设为 uint64 即可

RPRX avatar Jun 08 '25 10:06 RPRX

RatelimitedConn 的 Read() 有个问题,如果数据量大要等很久,或者直接卡死

应该改成 Write() 里有多少 token 就 write 多少数据

这个我想了一下不会卡死,但有多少 token 就 write 多少数据也不太行,调用方循环 write 会造成调用次数太多

只是说如果限速 1kb/s,但 target 发来一个 16kb 的 record,要等 16 秒。。。

RPRX avatar Jun 08 '25 10:06 RPRX

~~uint64,不是 int64~~

RPRX avatar Jun 08 '25 10:06 RPRX

没错吧, juju库要的burstBytesPerSec就是int64

配置允许的是uint64必须得做检查,超了就设为max

运行时的LimitAfter初始值得是 AfterBytes - BurstBytesPerSec 这里要的是int64 也得转换

Meo597 avatar Jun 08 '25 10:06 Meo597

我不确定 golang 里 uint64 转 int64 大于一半时会发生什么,你试一下,不过搞这么大还限什么速,所以 max 那里有点没必要

After 就直接传过去,不用减掉 burst

把 write 改回 read 吧,然后把 NewBucketWithRate 的逻辑合进去,也就是说直接传三个参数

RPRX avatar Jun 08 '25 10:06 RPRX