act_connmark

act_connmark

我有一个网络拓扑:

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

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 的手册页,但没有找到与您描述的类似的内容。我认为你可能想做这样的事情:

  1. 在“Server”中标记IP数据包的TOS字段。
  2. 让路由器对数据包进行特殊处理。
  3. 在“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
    

相关内容