Nftables 与 IP 数据包中的 TOS 值不匹配

Nftables 与 IP 数据包中的 TOS 值不匹配

这是在 Ubuntu 20.04 上。

我正在尝试为以下内容编写规则nftables它将匹配接口上收到的eth1具有特定 TOS 值 (0x02) 的所有 IP 数据包。到目前为止我的尝试:

sudo nft add table raw
sudo nft -- add chain raw prerouting {type filter hook prerouting priority -300\;}
sudo nft add rule ip raw prerouting iifname eth1 ip dscp 2 counter
sudo nft add rule ip raw prerouting iifname eth1 udp dport 41378 counter

我正在从一台单独的计算机向运行 nftables 的计算机发送 UDP 数据包。设置此发送套接字的代码,包括设置这些数据包中的 TOS:

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    int optval = 2;
    setsockopt(sockfd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)); //Set TOS value
  
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(41378);
    servaddr.sin_addr.s_addr = inet_addr("192.168.10.100");

我可以使用以下命令看到数据包到达sudo tcpdump -i eth1 -vv

14:51:35.153295 IP (tos 0x2,ECT(0), ttl 64, id 7091, offset 0, flags [DF], proto UDP (17), length 50)
    192.168.12.10.49089 > ubuntu.41378: [udp sum ok] UDP, length 22

这些的原始标头如下:

IP Header
    00 E0 4C 00 05 8B 3C 97 0E C7 E1 00 08 00 45 02         ..L...<.......E.
    00 31 7E 52                                             .1~R

解码后显示:

IP Header
   |-IP Version        : 4
   |-IP Header Length  : 5 DWORDS or 20 Bytes
   |-Type Of Service   : 2
   |-IP Total Length   : 49  Bytes(Size of Packet)
   |-Identification    : 32338
   |-TTL      : 64
   |-Protocol : 17
   |-Checksum : 8873
   |-Source IP        : 192.168.12.10
   |-Destination IP   : 192.168.12.100

问题当我跑步时sudo nft list ruleset我看到:

table ip raw {
        chain prerouting {
                type filter hook prerouting priority raw; policy accept;
                iifname "eth1" ip dscp 0x02 counter packets 0 bytes 0
                iifname "eth1" udp dport 41378 counter packets 8 bytes 392
        }
}

基于 udp 目的端口的规则匹配工作正常,但基于 0x02 的 dscp 的规则匹配工作不佳。

如何制定规则来匹配 TOS 0x02?

到目前为止,我已经尝试过 TOS 的其他值,以防 0x02 很特殊。我尝试了十进制 8、16、24 和 32。每次我看到带有我设置的 TOS 值的传入数据包,但 nfttables 规则从不计数,我相信这意味着它从不匹配。

方便的 nftables 指南: https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes

名称的 DSCP 值的便捷参考: https://www.cisco.com/c/en/us/td/docs/switches/datacenter/nexus1000/sw/4_0/qos/configuration/guide/nexus1000v_qos/qos_6dscp_val.pdf

答案1

进一步研究 IPv4 标头的构成: https://en.wikipedia.org/wiki/IPv4#Header

我看到 TOS 是给整个字节的名称,但 DSCP 仅是最高有效 6 位的名称。据此我猜测TOS != DSCP。我尝试将发送代码更改为使用 TOS 0x20,然后修改 nftables 规则来查找0x20 >> 2 == 0x08(将 TOS 右移两位以将其转换为 DSCP 值):

sudo nft add rule ip raw prerouting iifname eth1 ip dscp 0x8 counter

通过这一更改,我现在看到该新规则的计数器增加了。

table ip raw {
        chain prerouting {
                type filter hook prerouting priority raw; policy accept;
                iifname "eth1" ip dscp cs1 counter packets 12 bytes 590
                iifname "eth1" udp dport 41378 counter packets 12 bytes 590
        }
}

总括:

  • TOS 与 DSCP 不同。
  • DSCP 是 TOS 的最高有效 6 位。
  • 要使用 nftables 匹配 TOS ip dscp,请将 TOS 右移 2 位并匹配该值。

我确信这个答案缺少一些核心概念,因此我鼓励任何更了解这一点的人提供更有用的答案。

相关内容