Linux
iptables

Linux の iptables で OUTPUT 方向のパケットに ToS を設定する

More than 1 year has passed since last update.

扱っているプロトコルによってはまれに IP ToS を設定してパケットを送出したくなることがあります。
使ってるデーモンが対応しているなら適切に設定、もしくはソースを書き換えられるなら setsockopt(SO_PRIORITY) してパケットを送り出すように改造するといいと思います。

この文書では、IP ToS を設定してパケットを送出できないデーモンのパケットを、iptables で ToS 変更して送り出す場合を考えたいと思います。

お題: 外向きの ICMP パケットに IP Precedence 3 を設定する

cisco のルータとかだと policy-map の set ip precedence 3 で表現されるやつです。

解1: iptables の mangle table の OUTPUT chain の TOS target で --set-tos する

https://linuxjm.osdn.jp/html/iptables/man8/iptables-extensions.8.html

TOS
このモジュールは IPv4 ヘッダーの Type of Service フィールド (上位ビットも含む) や IPv6 ヘッダーの Priority フィールドを設定する。 TOS は DSCP と ECN と同じビットを共有する点に注意すること。 TOS ターゲットは mangle テーブルでのみ有効である。

--set-tos value[/mask]
mask で指定されたビットを 0 にし (下の「注意」を参照)、 value と TOS/Priority フィールド の XOR を取る。 mask が省略された場合は 0xFF とみなされる。

TOS ターゲットの --set-tos が使えれば目的を達成できそうです。TOS ターゲットは mangle テーブルでのみ使えるので、mangle テーブルの OUTPUT chain (下図の OUTPUT PATH 内の conntrack の次) にひっかけてみます。

https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg

--set-tos で指定する値についてですが、precedence は IP ToS/DSCP の上位 3 bit 部分なので、0x60 = 0110 0000(2) を指定します。

# iptables -t mangle -A OUTPUT --protocol icmp -j TOS --set-tos 0x60
# iptables -L -n -t mangle
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
TOS        icmp --  0.0.0.0/0            0.0.0.0/0            TOS set 0x60/0xff

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

image.png

こんな感じになります。今回は例として ICMP をひっかけましたが、お使いのデーモンがしゃべるプロトコルのポート番号などにひっかけるようにすれば TCP や UDP での応答にもひっかけられます。

解2: iptables の mangle table の OUTPUT chain で DSCP target で --set-dscp もしくは --set-dscp-class する

DSCP
このターゲットは、 IPv4 パケットの TOS ヘッダーにある DSCP ビットの値の書き換えを可能にする。 これはパケットを操作するので、 mangle テーブルでのみ使用できる。

--set-dscp value
DSCP フィールドの数値を設定する (10 進または 16 進)。
--set-dscp-class class
DSCP フィールドの DiffServ クラスを設定する。

DSCP ターゲットでも同様に書き換えできます。ひっかけられるのが mangle テーブルだけというのも TOS ターゲットと同じです。

今回は IP Precedence 3 を示す DSCP クラス名 CS3 で指定してみます

# iptables -t mangle -A OUTPUT --protocol icmp -j DSCP --set-dscp-class CS3
# iptables -L -n -t mangle
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DSCP       icmp --  0.0.0.0/0            0.0.0.0/0            DSCP set 0x18

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

image.png

--set-tos の場合と ToS (DiffServ) フィールドの値は同じになります。