我有一个网络拓扑:
Server <-> router1 <-> router2 <-> router3 <-> edgeRouter <-> "internet"
所有路由器都是基于linux的,并且支持iptables。
服务器使用 iptables ( --set class X:Y
) 设置流量类别,路由器根据设置的类别进行一些“路由”。 (类别取决于原始应用程序)。
边缘路由器通过我们的 ISP 将数据包转发到互联网,并接收返回(回复)数据包。收到的回复当然没有设置流量类别。
是否可以iptables
在边缘路由器上使用规则(mangle 或类似的东西)来跟踪返回数据包(NAT 样式,来自“ESTABLISHED”连接的数据包)并使用与原始数据包相同的流量类别来标记返回数据包包?在边缘路由器上启用 NAT 不是问题。
TLDR:如何使用 iptables 对同一连接的与出口具有相同类别的入口数据包进行分类。
答案1
TLDR:如何使用 iptables 对同一连接的与出口具有相同类别的入口数据包进行分类。
您的问题并不完全清楚您指的是哪种分类方法,但一般来说,如果我们谈论使用tc
和排队规则的流量整形,则适用以下内容。
act_connmark
由于入口 qdisc 处理是在 netfilter 之前完成的,因此您无法使用 iptables 直接对入口流量进行分类(无需使用 IMQ 重新编译内核,请参见下文)。但是,您可以使用连接跟踪间接对其进行分类。如果您的内核上可用,您可以使用 act_connmark 模块,该模块专为此目的而设计,该模块向支持它的过滤器添加了一个connmark
操作。tc
# 0. Load modules and IFB device
modprobe act_connmark
modprobe ifb
ip link set ifb0 up
# 1. Classify packets by marking them
iptables -t mangle -A POSTROUTING -p tcp --sport 22 -j MARK --set-mark 1
# 2. Append rule to save the packet mark to the connection mark
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark
# 3. Restore the connection mark to the packet mark with 'action connmark'
# before redirecting to the ifb-device
tc qdisc add dev eth0 handle ffff: ingress
tc qdisc add dev ifb0 handle 1: root
tc filter add dev eth0 parent ffff: prio 1 \
protocol ip u32 match u32 0 0 flowid ffff:1 \
action connmark \
action mirred egress redirect dev ifb0
# 4. Apply filters to classify packets based on their mark
# ... setup qdiscs and classes as usual on ifb0... then
tc filter add dev ifb0 parent 1: prio 1 protocol ip handle 1 fw classid 1:01
- 示例位于ArchLinux 维基
IMQ
据我了解,IMQ(中间队列设备)通过在 netfilter 处理后通过虚拟设备将其循环回来,从而绕过内核中的正常流量。它不与内核树合并,因此不包含在大多数发行版中,并且需要您自己打补丁并编译内核。如果你这样做,它会像这样工作:
# classify and save mark in POSTROUTING as before... then
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -j IMQ --todev 0
# ... setup qdiscs and classes as usual on imq0 ... then
tc filter add dev imq0 parent 1: prio 1 protocol ip handle 1 fw classid 1:01
这还将使您能够使用 iptables 对入口进行更高级的分类,使用普通的 u32 过滤器(例如任意端口范围)可能会非常麻烦。不过,我无法谈论这个解决方案的性能或优雅,我猜想它从未被合并是有原因的。
答案2
由于您的出口数据包具有基于应用程序的类别集(并且我猜测每个应用程序都使用一组特定的 TCP/UDP 端口),因此您可以根据这些端口对传入数据包进行重新分类。
例如。在 EdgeRouter 上重新分类已建立的(出站)HTTP 会话:
iptables -t mangle -A INPUT -i [WANIF] -m state --state ESTABLISHED,RELATED -p tcp -m tcp --sport 80 -j DSCP --set-dscp-class cs3
注意:可能需要使用 FORWARD 表而不是 INPUT ...
但是 - 要跟踪出口数据包,确定它们在出去时具有什么类别,然后将同一类别应用于同一流的入口数据包 - 仍然是可能的,但工作量很大,并且可能需要与 conntrack 接口的自定义网络过滤器模块。
答案3
你用什么设置的--set class X:Y
?究竟是什么类?我搜索了 iptables 的手册页,但没有找到与您描述的类似的内容。我认为你可能想做这样的事情:
- 在“Server”中标记IP数据包的TOS字段。
- 让路由器对数据包进行特殊处理。
在“edgeRouter”中执行以下操作:
# If a packet arrives from LAN, is marked and we know nothing about the #+ connection, then mark the connection iptables -t mangle -A PREROUTING -i $LAN_IF -m tos --tos $TOS_VAL -m \ connmark \! --mark $TOS_VAL -j CONNMARK --set-xmark $TOS_VAL # Reset the TOS value when going out to prevent strange interpretation iptables -t mangle -A POSTROUTING -o $WAN_IF -m tos --tos $TOS_VAL \ -j TOS --set-tos 0x00 # If a packet arrives from WAN and the connection is marked, then mark #+ the packet so that the routers in LAN know how to deal with it iptables -t mangle -A PREROUTING -i $WAN_IF -m connmark --mark $TOS_VAL \ -j TOS --set-tos $TOS_VAL