TTLでサブネット内を区別（iptables）

# TTLの値でサブネットワークを分ける
久しぶりに昔の本職ネタとして、大昔に前の会社でやったことの復習。結果として、当時使ったiptablesのオプションとは異なるような、、。（それだけスキルが維持されていない。）

## 意図
あるプロジェクトで、同じサブネット内であっても、場所を区別したいことがあった。例えば、次のような構成。
![構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/963dfd17-7e23-cdf8-5e9f-a322554f5183.png)
192.168.1.0/24というネットワークに、ネットワークブリッジを隔てて２つの領域（Area1とArea2）とがある。各種事情があって（もう忘れたがPayloadを変えたくない理由があったのであろう）、iptablesおよびTTLを使って２つの領域を分けることとした。

## 構成
ここでは上図をVirtualboxを使って実現する。Virtualboxの設定およびネットワークブリッジの設定は[以前の記事](https://qiita.com/infinite1oop/items/3c479b775cc138c7bb46)と同じ。一部下記に再掲。

```
~# 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自体のマニュアルは[こちら](https://linuxjm.osdn.jp/html/iptables/man8/iptables-extensions.8.html)。

### 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"になっていることが必須のようだ。こんな[記事](https://forum.openwrt.org/t/iptables-ttl-mangling-doesnt-work-with-bridged-setup/32708)が参照。

ちなみに、毎回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
[ここ](https://www.linuxtopia.org/Linux_Firewall_iptables/x4799.html)にもあるように、以前は下記コマンドで動作した記憶もあったが、今回は動作せずNG。

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

そのかわり、[ここ](https://forum.openwrt.org/t/iptables-ttl-mangling-doesnt-work-with-bridged-setup/32708)を参考にして、下記コマンドで動作するようだった。

```
~# 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では動作せず。）

## 確認の様子
最初の図の端末１から端末２へ、TTLを200に設定してpingする。

```
~# ping -c 1 -t 200 192.168.1.12
```

### 端末１でのWireshark
![Src.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/7870f072-383a-b6b7-7426-4dac7b671408.png)
TTLは、pingオプションで明示的に設定した200。

### 端末２でのWireshark
![Dst.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/9644ab52-54c5-7d52-49a4-b7d63bccb324.png)
ネットワークブリッジのiptablesで3減り、TTLは197となっている。

## 終わりに
iptablesは奥が深いことをあらためて悟る。