这是在 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 位并匹配该值。
我确信这个答案缺少一些核心概念,因此我鼓励任何更了解这一点的人提供更有用的答案。