TTLでサブネット内を区別(iptables)


TTLの値でサブネットワークを分ける

久しぶりに昔の本職ネタとして、大昔に前の会社でやったことの復習。結果として、当時使ったiptablesのオプションとは異なるような、、。(それだけスキルが維持されていない。)

意図

あるプロジェクトで、同じサブネット内であっても、場所を区別したいことがあった。例えば、次のような構成。

192.168.1.0/24というネットワークに、ネットワークブリッジを隔てて2つの領域(Area1とArea2)とがある。各種事情があって(もう忘れたがPayloadを変えたくない理由があったのであろう)、iptablesおよびTTLを使って2つの領域を分けることとした。

構成

ここでは上図をVirtualboxを使って実現する。Virtualboxの設定およびネットワークブリッジの設定は以前の記事と同じ。一部下記に再掲。

~# cat /etc/network/interfaces
auto eth0
iface eth0 inet static
  address 0.0.0.0
auto eth1
iface eth1 inet static
  address 0.0.0.0
auto br0
iface br0 inet static
  address 0.0.0.0
  bridge_ports eth0 eth1

~# brctl show
bridge name bridge id       STP enabled interfaces
br0     8000.080027507ba3   no          eth0                                                                           eth1
~# ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 08:00:27:50:7b:a3  txqueuelen 1000  (Ethernet)
        RX packets 6  bytes 336 (336.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 79  bytes 29072 (28.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 08:00:27:84:d4:75  txqueuelen 1000  (Ethernet)
        RX packets 43  bytes 3142 (3.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 201  bytes 61286 (59.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 08:00:27:50:7b:a3  txqueuelen 1000  (Ethernet)
        RX packets 43  bytes 3142 (3.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 201  bytes 61286 (59.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 12886  bytes 953420 (931.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 12886  bytes 953420 (931.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

IPv6アドレスがアサインされているが、ここでは無視。

ネットワークブリッジにiptablesを適用

iptables自体のマニュアルはこちら

br_netfilter

以前はiptablesだけでもOKだったような気がするのだが、今回は、br_netfilterというカーネルモジュールを意図的にロードする必要があった。以前の記録は残っていないし、今回用いたLinuxのDistribution(かつカーネルバージョン)も違うので、なんとも言えず。

~# modprobe br_netfilter
~# sysctl -a | grep bridge
net.bridge.bridge-nf-call-arptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-filter-pppoe-tagged = 0
net.bridge.bridge-nf-filter-vlan-tagged = 0
net.bridge.bridge-nf-pass-vlan-input-dev = 0

iptables利用には、”net.bridge.bridge-nf-call-iptables”が"1"になっていることが必須のようだ。こんな記事が参照。

ちなみに、毎回modprobeせず、起動時に自動的にロードするには、/etc/modulesに記載すればよし。

~# cat /etc/modules 
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.

br_netfilter

iptables

ここにもあるように、以前は下記コマンドで動作した記憶もあったが、今回は動作せずNG。

~# iptables -t mangle -A PREROUTING -i eth0 -j TTL --ttl-dec 3

そのかわり、ここを参考にして、下記コマンドで動作するようだった。

~# iptables -t mangle -A PREROUTING -j TTL --ttl-dec 3

ただし、これだと、最初の図のArea2からArea1へのIPパケットのTTLも減ってしまうので、

~# iptables -t mangle -A PREROUTING -s 192.168.1.11 -j TTL --ttl-dec 3

のように、Area1内の特定の送信アドレスを指定することとした。オプションの詳細は、iptablesのマニュアルを確認するとよいだろう。

なお、PREROUTINGの代わりにPOSTROUTINGやFORWARDでもOKの様子。(ただし、INPUT/OUTPUTでは動作せず。)

確認の様子

最初の図の端末1から端末2へ、TTLを200に設定してpingする。

~# ping -c 1 -t 200 192.168.1.12

端末1でのWireshark


TTLは、pingオプションで明示的に設定した200。

端末2でのWireshark


ネットワークブリッジのiptablesで3減り、TTLは197となっている。

終わりに

iptablesは奥が深いことをあらためて悟る。