Linux:通过结合 tc 与 iptables 来限制特定端口速率无法按预期工作

Linux:通过结合 tc 与 iptables 来限制特定端口速率无法按预期工作

该脚本尝试限制端口 2000 的传入速率,当使用 iptables 标记INPUT数据包时不起作用,但OUTPUT可以正常工作。

我使用nc -kl 2000这台机器10.0.1.54iperf -c 10.0.1.54 -p 2000 -t 10另一台机器来测试它。

为什么OUTPUT有效 但 无效 呢INPUT

dev=enp3s0
ip_addr=10.0.1.54
ip_port=2000

rate_limit=20kbit
htb_class=10

if [ "$(id -u)" != "0" ]; then
    echo "This script must be run as root" 1>&2
    exit 1
fi

if [ "$1" = "enable" ]; then
    echo "enabling rate limits"
    tc qdisc del dev $dev root > /dev/null 2>&1
    tc qdisc add dev $dev root handle 1: htb

    tc class add dev $dev parent 1: classid 1:$htb_class htb rate $rate_limit ceil $rate_limit
    tc filter add dev $dev parent 1: prio 0 protocol ip handle $htb_class fw flowid 1:$htb_class

    # marking the INPUT chain does dot work as expected
    #iptables -t mangle -A INPUT -d $ip_addr -p tcp --dport $ip_port -j MARK --set-mark $htb_class

    # marking the OUTPUT chain works fine
    iptables -t mangle -A OUTPUT -s $ip_addr -p tcp --sport $ip_port -j MARK --set-mark $htb_class
elif [ "$1" = "disable" ]; then
    echo "disabling rate limits"
    tc qdisc del dev $dev root > /dev/null 2>&1

    #iptables -t mangle -D INPUT -d $ip_addr -p tcp --dport $ip_port -j MARK --set-mark $htb_class
    iptables -t mangle -D OUTPUT -s $ip_addr -p tcp --sport $ip_port -j MARK --set-mark $htb_class
elif [ "$1" = "show" ]; then
    tc qdisc show dev $dev
    tc class show dev $dev
    tc filter show dev $dev
    iptables -t mangle -vnL INPUT
    iptables -t mangle -vnL OUTPUT
else
    echo "invalid arg $1"
fi

答案1

我尝试通过列出以下链接来回答这个问题:

流量整形有两种模式:INGRESS 和 EGRESS。INGRESS 处理传入流量,EGRESS 处理传出流量。Linux 不支持对 INGRESS 进行整形/排队,只支持监管。因此存在 IFB,我们可以将其附加到 INGRESS 队列,同时我们可以将任何常规排队(如 FQ_CODEL)添加为 IFB 设备上的 EGRESS 队列。[http://wiki.gentoo.org/wiki/Traffic_shaping]

所以,我对这个问题的解决方案是:

#!/bin/bash

dev=enp3s0
ifb_dev=ifb0
ip_addr=10.0.1.54
ip_port=2000

rate_limit=20kbit
htb_class=10

if [ "$(id -u)" != "0" ]; then
    echo "This script must be run as root" 1>&2
    exit 1
fi

modprobe ifb
ifconfig ifb0 up

if [ "$1" = "enable" ]; then
    echo "enabling rate limits"

    tc qdisc add dev $dev handle ffff: ingress
    tc filter add dev $dev parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $ifb_dev

    tc qdisc add dev $ifb_dev root handle 1: htb
    tc class add dev $ifb_dev parent 1: classid 1:$htb_class htb rate $rate_limit ceil $rate_limit

    tc filter add dev $ifb_dev parent 1: protocol ip prio 1000 u32 match ip dport 2001 0xffff flowid 1:$htb_class

elif [ "$1" = "disable" ]; then
    echo "disabling rate limits"

    tc qdisc del dev $dev root > /dev/null 2>&1
    tc qdisc del dev $dev ingress > /dev/null 2>&1
    tc qdisc del dev $ifb_dev root > /dev/null 2>&1
    tc qdisc del dev $ifb_dev ingress > /dev/null 2>&1

elif [ "$1" = "show" ]; then

    tc qdisc show dev $dev
    tc class show dev $dev
    tc filter show dev $dev

else
    echo "invalid arg $1"
fi

答案2

金正说得对,你无法控制入口流量。但你可以像杰克船长那样......改变事实。

使用“重定向网关”在您的主机和 vps 之间创建一个 openvpn 连接,以便所有流量都通过 vps。因此它看起来像这样:您的家庭网络/电脑 -> 互联网 -> vps -> 互联网

对于您的家庭网络来说,INGRESS 是 VPS 的 EGRESS,然后在 VPS 上塑造传出接口。

一些提示:请记住指定您的家庭网络/ip,否则您将杀死 vps 上传速率。vps 必须具有比您的家庭网络更好的带宽,测量带宽。在德国,您只需从 hetzner.de 购买 7 欧元的 vps,它们非常可靠。

答案3

没必要这么做,很简单,你只需要修补内核和 iptables,然后你就可以调整传入流量了,+ 如果你使用 LXC,那么你甚至不需要修补任何东西,只需在 KVM 上

相关内容