IBM Cloud: 複数インターフェースを持つVSIのeth0以外となぜ通信できないのか？

#1. はじめに

IBM CloudのVPCにて、以下のような構成時に、

- Server-A(172.16.0.4)からServer-Bの１つ目のInterfaceであるeth0のある172.16.4.2にはpingが通りる。
- しかし、Server-AからServer-Bのeth1-eth3のIPにはpingが通らない。

と言われました。なぜでしょうか？それを理解するのがこの記事の目的です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/75c937b0-3c84-a87c-66d9-6e80c948d42e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/6c25db81-8bd9-edec-b00f-a7ddbe40801c.png)

```
[root@server-a ~]# ping -c 3 172.16.4.2
PING 172.16.4.2 (172.16.4.2) 56(84) bytes of data.
64 bytes from 172.16.4.2: icmp_seq=1 ttl=64 time=3.86 ms
64 bytes from 172.16.4.2: icmp_seq=2 ttl=64 time=0.444 ms
64 bytes from 172.16.4.2: icmp_seq=3 ttl=64 time=0.455 ms

--- 172.16.4.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 0.444/1.589/3.868/1.611 ms

[root@server-a ~]# ping -c 3 172.16.5.4
PING 172.16.5.4 (172.16.5.4) 56(84) bytes of data.
（出力なし）

[root@server-a ~]# ping -c 3 172.16.6.4
PING 172.16.6.4 (172.16.6.4) 56(84) bytes of data.
（出力なし）

[root@server-a ~]# ping -c 3 172.16.7.4
PING 172.16.7.4 (172.16.7.4) 56(84) bytes of data.
（出力なし）
```

#2. Server-Bでtcpdumpを取得する

こういう問題を解析するのに役立つのは（いつものことですが）tcpdumpです。

```txt:Server-AからServer-B(eth1)へのpingは失敗
[root@server-a ~]# ping -c 3 172.16.5.4
PING 172.16.5.4 (172.16.5.4) 56(84) bytes of data.

（応答なし）

```

```txt:Server-B(eth1)には届いているが、応答はしていない。
[root@server-b ~]# tcpdump -i any icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes

02:17:49.498516 IP 172.16.0.4 > 172.16.5.4: ICMP echo request, id 14512, seq 1, length 64
02:17:50.497642 IP 172.16.0.4 > 172.16.5.4: ICMP echo request, id 14512, seq 2, length 64
02:17:51.497650 IP 172.16.0.4 > 172.16.5.4: ICMP echo request, id 14512, seq 3, length 64
```

Server-Bでtcpdumpを取ってみると、パケット自体は届いていることがわかります。つまり、Security Groupなどでブロックされているというわけではなさそうです。
また、受信したパケットの応答をしていないことから、原因はServer-B自身にありそうだという目星が付きます。

#3. Server-Bで経路情報を確認する

Server-A(172.16.0.4)からServer-B(172.16.5.4)への応答は、もちろん

- Source IPが172.16.5.4
- Destination IPが172.16.0.4

であるべきです。この場合Server-Bはどういう経路を使うのでしょうか？

```
[root@server-b ~]# ip r
default via 172.16.4.1 dev eth0
169.254.0.0/16 dev eth0 scope link metric 1002
172.16.4.0/24 dev eth0 proto kernel scope link src 172.16.4.2
172.16.5.0/24 dev eth1 proto kernel scope link src 172.16.5.4
172.16.6.0/24 dev eth2 proto kernel scope link src 172.16.6.4
172.16.7.0/24 dev eth3 proto kernel scope link src 172.16.7.4
```

```172.16.0.4への経路はどこが使われるか？
[root@server-b ~]# ip route get 172.16.0.4
172.16.0.4 via 172.16.4.1 dev eth0 src 172.16.4.2
    cache
```

つまり、**Server-A(172.16.0.4)には、eth0経由で送信する設定になっています。eth1でパケットを受信したにも関わらずです！**。
このような受信したインターフェースと返信するインターフェースが異なるネットワーク構成は非対称ルーティングと呼ばれており、デフォルトでは許可されていません。

```
[root@syasuda-router ~]# sysctl -ar '\.rp_filter'
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
net.ipv4.conf.eth2.rp_filter = 1
net.ipv4.conf.eth3.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 0
```

https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

```
rp_filter - INTEGER
	0 - No source validation.
	1 - Strict mode as defined in RFC3704 Strict Reverse Path
	    Each incoming packet is tested against the FIB and if the interface
	    is not the best reverse path the packet check will fail.
	    By default failed packets are discarded.
	2 - Loose mode as defined in RFC3704 Loose Reverse Path
	    Each incoming packet's source address is also tested against the FIB
	    and if the source address is not reachable via any interface
	    the packet check will fail.

	Current recommended practice in RFC3704 is to enable strict mode
	to prevent IP spoofing from DDos attacks. If using asymmetric routing
	or other complicated routing, then loose mode is recommended.

	The max value from conf/{all,interface}/rp_filter is used
	when doing source validation on the {interface}.

	Default value is 0. Note that some distributions enable it
	in startup scripts.
```

#4. 解決策

案1: [eth1で受信したパケットをeth0経由で返すことを許可するようにカーネルパラメーターを変更する。](https://qiita.com/testnin2/items/ec2c0f3b626699f1c326)
案2: [eth1で受信したパケットはeth1で返すようにポリシーベースルーティングを構成する。](https://qiita.com/testnin2/items/635787697e59ab94ce98)

案1は非対称ルーティングを許可するということなので、それに応じた脆弱性も甘受する必要があります。またeth0のIP Spoofingも有効にする必要があります。よって、もしeth1-eth3に通信させる必要があるのであれば、個人的には案2の方を推奨します。具体的な手順についてはそれぞれの案におけるリンク先をご参照下さい。