我们有一个 Cisco 路由器,它允许速率限制(他们称之为监管),但允许基于每个 TCP 连接的突发。例如,我们可以将带宽上限限制为 50Mbit,但直到传输了 4MB 后才会施加上限。这是针对每个建立的 TCP 连接强制执行的。
在 Linux 下有什么方法可以做到这一点吗?另外,这种解决方案有什么缺点吗?如果它对任何人都有帮助,用于设置突发的 Cisco 命令是在策略映射下运行的 Police 命令的第三个参数(至少在我们的 ASA 5505 上)。
这样做的目的是让服务器能够利用 95/5 突发并尽可能快地为普通用户提供网页服务,但减少超过 5% 的时间突发的机会(例如,如果执行服务器到服务器传输或从网站下载大文件)。据我所知,对于持续时间过长的 DDoS 攻击,这可能不是一个解决方案,但由于各种原因,这不是一个问题。
答案1
这在 linux 中可以通过iptables
和实现tc
。您可以将 iptables 配置为MARK
已传输一定数量字节的连接上的数据包。然后,您可以tc
将这些标记的数据包放入排队规则中的一个类中,以对带宽进行速率限制。
一个有点棘手的部分是限制上传和下载的连接。tc
不支持入口流量整形。您可以通过在面向网络服务器的接口上调整出口(这将影响到您的网络服务器的下载)以及在面向上游提供商的接口上调整出口(这将影响从您的网络服务器的上传)来解决此问题。您并没有真正调整入口(下载)流量,因为您无法控制上游提供商发送数据的速度。但是,调整面向网络服务器的接口将导致数据包被丢弃,并且上传者会缩小其 TCP 窗口以适应带宽限制。
示例:(假设这是在基于 Linux 的路由器上,其中面向 Web 服务器的接口是eth0
,上游是eth1
)
# mark the packets for connections over 4MB being forwarded out eth1
# (uploads from webserver)
iptables -t mangle -A FORWARD -p tcp -o eth1 -m connbytes --connbytes 4194304: --connbytes-dir both --connbytes-mode bytes -j MARK --set-mark 50
# mark the packets for connections over 4MB being forwarded out eth0
# (downloads to webserver)
iptables -t mangle -A FORWARD -p tcp -o eth0 -m connbytes --connbytes 4194304: --connbytes-dir both --connbytes-mode bytes -j MARK --set-mark 50
# Setup queuing discipline for server-download traffic
tc qdisc add dev eth0 root handle 1: htb
tc class add dev eth0 parent 1: classid 1:50 htb rate 50mbit
# Setup queuing discipline for server-upload traffic
tc qdisc add dev eth1 root handle 1: htb
tc class add dev eth1 parent 1: classid 1:50 htb rate 50mbit
# set the tc filters to catch the marked packets and direct them appropriately
tc filter add dev eth0 parent 1:0 protocol ip handle 50 fw flowid 1:50
tc filter add dev eth1 parent 1:0 protocol ip handle 50 fw flowid 1:50
如果您想在网络服务器本身而不是 Linux 路由器上执行此操作,您仍然可以使用上述内容的上传部分。一个值得注意的变化是您将替换FOWARD
为OUTPUT
.要下载,您需要使用“中间功能块”设备或 来设置排队规则ifb
。简而言之,它使用虚拟接口,以便您可以将入口流量视为出口流量,并使用tc
.有关如何设置的更多信息ifb
可以在这里找到:https://serverfault.com/questions/350023/tc-ingress-policing-and-ifb-mirroring
请注意,此类内容往往需要进行大量调整才能扩展。一个紧迫的问题是connbytes
依赖于conntrack
模块,它往往会遇到大量连接的扩展墙。我建议进行重负载测试。
另一个需要注意的是,这对于 UDP 根本不起作用,因为它是无状态的。还有其他技术可以解决这个问题,但看起来您的要求仅针对 TCP。
另外,要撤消上述所有操作,请执行以下操作:
# Flush the mangle FORWARD chain (don't run this if you have other stuff in there)
iptables -t mangle -F FORWARD
# Delete the queuing disciplines
tc qdisc del dev eth0 root
tc qdisc del dev eth1 root