1. はじめに
protocol state filtering
という機能がリリースされたので、この機能の紹介と機能検証を実施します。ドキュメントはこちら。
- https://cloud.ibm.com/docs/vpc?topic=vpc-release-notes&locale=en#vpc-may3124
- https://cloud.ibm.com/docs/vpc?topic=vpc-vni-about&locale=en#protocol-state-filtering
2. protocol state filtering とは
VNIは、IBM Cloudのサーバーに付与されるネットワークインターフェースです。(より厳密なVNIとは何かについての詳細は、IBM Cloud: Network Attachments/Virtual Network Interface(VNI)方式とLegacy Network Interface方式の違い を参照してください。)。
-
サーバーにVNI1/VNI2という2つのインターフェースが存在する場合、下図のようにVNI1に入ってきたパケットがVNI1から戻り、VNI2に入ってきたパケットがVNI2から戻っていく、つまり通信経路が対称的であれば特に問題はありません。
-
しかし、サーバーの初期構成のrouting tableでは、default gatewayがVNI1側のインターフェースに対して構成されているため、VNI2からサーバーに入ってきたパケットがクライアントに返る際にはVNI1側から返ろうとします(非対称ルーティング)。これを避けて、通信経路を対称的にするためには、ここで設定したように、policy based routingなどの特別な構成が必要になります。
- 一般的に、主なLinux環境のデフォルト構成では、このようなパケットが入ってきたインターフェースとパケットが出ていくインターフェースが異なるような非対称ルーティングはブロックされています。この非対称ルーティングをブロックしているのはLinux Kernelにおける
rp_filter
というパラメーターです。以下のKBも参考になります。細かいことは省きますが、要はrp_filter
を2にすると非対称ルーティングは可能になります。 - これに加えて、IBM CloudのVPCでは、VNIにて
TCP Connection の protocol state
をチェックしています。そのため、VNI1からパケットを戻ろうとした際に、このパケットはdropされてしまいます。
- 一般的に、主なLinux環境のデフォルト構成では、このようなパケットが入ってきたインターフェースとパケットが出ていくインターフェースが異なるような非対称ルーティングはブロックされています。この非対称ルーティングをブロックしているのはLinux Kernelにおける
-
今回の新機能において、TCP Connection の protocol state をチェックしないようにすることができるようになりました。これによって、VNI1からパケットを戻ろうとした際に、パケットがdropされることはありません。
protocol state filtering においては、他に以下の注意点があります。
- defaultの設定値は
auto
です。このauto
の値は、以下のとおり。- Bare Metal Server では
disabled
- VSIでは
enabled
- File share mount target では
enabled
- Bare Metal Server では
- ICMPには関係ない。例えば、pingは
protocol state filtering
の値に関係なく応答する。 - Floating IP経由でのアクセス(インターネットからのアクセス)における非対称ルーティング構成は、
protocol state filtering
を無効にしただけでは本稿執筆時点のVPCではまだ動かない。同一VPCからのアクセスや、異なるVPCからのTGW経由でのアクセスの際であれば、protocol state filtering
を無効にするだけで機能する。
検証環境
[root@syasuda-vni-test1 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 02:00:05:02:70:58 brd ff:ff:ff:ff:ff:ff
altname enp0s3
altname ens3
inet 10.0.0.11/24 brd 10.0.0.255 scope global dynamic noprefixroute eth0
valid_lft 304sec preferred_lft 304sec
inet6 fe80::5ff:fe02:7058/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 02:00:25:02:70:58 brd ff:ff:ff:ff:ff:ff
altname enp0s4
altname ens4
inet 10.0.0.12/24 brd 10.0.0.255 scope global dynamic noprefixroute eth1
valid_lft 235sec preferred_lft 235sec
inet6 fe80::643b:5cef:7e46:542a/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[root@syasuda-vni-target ~]# ip r
default via 10.0.0.1 dev eth0
default via 10.0.0.1 dev eth0 proto dhcp src 10.0.0.11 metric 100
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.11 metric 100
10.0.0.0/24 dev eth1 proto kernel scope link src 10.0.0.12 metric 101
検証1: VSIプロビジョニング直後の構成
[root@syasuda-client ~]# ping 10.0.0.12
PING 10.0.0.12 (10.0.0.12) 56(84) bytes of data.
^C
--- 10.0.0.12 ping statistics ---
6 packets transmitted, 0 received, 100% packet loss, time 5114ms
[root@syasuda-vni-target ~]# tcpdump -i any icmp or port 80 -nn
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
02:11:12.840133 eth1 In IP 10.8.0.4 > 10.0.0.12: ICMP echo request, id 4, seq 1, length 64
02:11:13.858275 eth1 In IP 10.8.0.4 > 10.0.0.12: ICMP echo request, id 4, seq 2, length 64
02:11:14.882252 eth1 In IP 10.8.0.4 > 10.0.0.12: ICMP echo request, id 4, seq 3, length 64
02:11:15.906330 eth1 In IP 10.8.0.4 > 10.0.0.12: ICMP echo request, id 4, seq 4, length 64
02:11:16.930260 eth1 In IP 10.8.0.4 > 10.0.0.12: ICMP echo request, id 4, seq 5, length 64
02:11:17.954309 eth1 In IP 10.8.0.4 > 10.0.0.12: ICMP echo request, id 4, seq 6, length 64
[root@syasuda-client ~]# curl 10.0.0.12
(応答なし)
[root@syasuda-vni-target ~]# tcpdump -i any icmp or port 80 -nn
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
02:11:48.023862 eth1 In IP 10.8.0.4.37694 > 10.0.0.12.80: Flags [S], seq 3995821265, win 32120, options [mss 1460,sackOK,TS val 1211393662 ecr 0,nop,wscale 7], length 0
02:11:49.058427 eth1 In IP 10.8.0.4.37694 > 10.0.0.12.80: Flags [S], seq 3995821265, win 32120, options [mss 1460,sackOK,TS val 1211394697 ecr 0,nop,wscale 7], length 0
02:11:51.106363 eth1 In IP 10.8.0.4.37694 > 10.0.0.12.80: Flags [S], seq 3995821265, win 32120, options [mss 1460,sackOK,TS val 1211396745 ecr 0,nop,wscale 7], length 0
02:11:55.138333 eth1 In IP 10.8.0.4.37694 > 10.0.0.12.80: Flags [S], seq 3995821265, win 32120, options [mss 1460,sackOK,TS val 1211400777 ecr 0,nop,wscale 7], length 0
検証2: rp_filterを変更した構成
[root@syasuda-vni-target ~]# sysctl -a |grep '\.rp_filter'
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 1
[root@syasuda-vni-target ~]# sysctl -w net.ipv4.conf.all.rp_filter=2
[root@syasuda-vni-target ~]# sysctl -w net.ipv4.conf.default.rp_filter=2
[root@syasuda-vni-target ~]# sysctl -a |grep '\.rp_filter'
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 1
[root@syasuda-client ~]# ping 10.0.0.12
PING 10.0.0.12 (10.0.0.12) 56(84) bytes of data.
64 bytes from 10.0.0.12: icmp_seq=1 ttl=56 time=1.89 ms
64 bytes from 10.0.0.12: icmp_seq=2 ttl=56 time=1.92 ms
64 bytes from 10.0.0.12: icmp_seq=3 ttl=56 time=1.84 ms
64 bytes from 10.0.0.12: icmp_seq=4 ttl=56 time=1.68 ms
64 bytes from 10.0.0.12: icmp_seq=5 ttl=56 time=1.77 ms
^C
--- 10.0.0.12 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4007ms
rtt min/avg/max/mdev = 1.683/1.820/1.923/0.086 ms
[root@syasuda-vni-target ~]# tcpdump -i any icmp or port 80 -nn
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
02:12:33.654077 eth1 In IP 10.8.0.4 > 10.0.0.12: ICMP echo request, id 5, seq 1, length 64
02:12:33.654128 eth0 Out IP 10.0.0.12 > 10.8.0.4: ICMP echo reply, id 5, seq 1, length 64
02:12:34.656216 eth1 In IP 10.8.0.4 > 10.0.0.12: ICMP echo request, id 5, seq 2, length 64
02:12:34.656263 eth0 Out IP 10.0.0.12 > 10.8.0.4: ICMP echo reply, id 5, seq 2, length 64
02:12:35.657168 eth1 In IP 10.8.0.4 > 10.0.0.12: ICMP echo request, id 5, seq 3, length 64
02:12:35.657225 eth0 Out IP 10.0.0.12 > 10.8.0.4: ICMP echo reply, id 5, seq 3, length 64
02:12:36.659065 eth1 In IP 10.8.0.4 > 10.0.0.12: ICMP echo request, id 5, seq 4, length 64
02:12:36.659110 eth0 Out IP 10.0.0.12 > 10.8.0.4: ICMP echo reply, id 5, seq 4, length 64
02:12:37.660991 eth1 In IP 10.8.0.4 > 10.0.0.12: ICMP echo request, id 5, seq 5, length 64
02:12:37.661017 eth0 Out IP 10.0.0.12 > 10.8.0.4: ICMP echo reply, id 5, seq 5, length 64
[root@new-syasuda-tok1-vpc1 ~]# curl 10.0.0.12
(応答なし)
[root@syasuda-client ~]# tcpdump -i any icmp or port 80 -nn
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
02:22:29.579725 eth0 Out IP 10.8.0.4.56488 > 10.0.0.12.80: Flags [S], seq 2134132328, win 32120, options [mss 1460,sackOK,TS val 1212035220 ecr 0,nop,wscale 7], length 0
02:22:30.592493 eth0 Out IP 10.8.0.4.56488 > 10.0.0.12.80: Flags [S], seq 2134132328, win 32120, options [mss 1460,sackOK,TS val 1212036233 ecr 0,nop,wscale 7], length 0
02:22:32.640496 eth0 Out IP 10.8.0.4.56488 > 10.0.0.12.80: Flags [S], seq 2134132328, win 32120, options [mss 1460,sackOK,TS val 1212038281 ecr 0,nop,wscale 7], length 0
02:22:36.672515 eth0 Out IP 10.8.0.4.56488 > 10.0.0.12.80: Flags [S], seq 2134132328, win 32120, options [mss 1460,sackOK,TS val 1212042313 ecr 0,nop,wscale 7], length 0
[root@syasuda-vni-target ~]# tcpdump -i any icmp or port 80 -nn
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
02:22:29.581629 eth1 In IP 10.8.0.4.56488 > 10.0.0.12.80: Flags [S], seq 2134132328, win 32120, options [mss 1460,sackOK,TS val 1212035220 ecr 0,nop,wscale 7], length 0
02:22:29.581687 eth0 Out IP 10.0.0.12.80 > 10.8.0.4.56488: Flags [S.], seq 2110509886, ack 2134132329, win 31856, options [mss 1460,sackOK,TS val 600171014 ecr 1212035220,nop,wscale 7], length 0
02:22:30.583361 eth0 Out IP 10.0.0.12.80 > 10.8.0.4.56488: Flags [S.], seq 2110509886, ack 2134132329, win 31856, options [mss 1460,sackOK,TS val 600172016 ecr 1212035220,nop,wscale 7], length 0
02:22:30.594473 eth1 In IP 10.8.0.4.56488 > 10.0.0.12.80: Flags [S], seq 2134132328, win 32120, options [mss 1460,sackOK,TS val 1212036233 ecr 0,nop,wscale 7], length 0
02:22:30.594492 eth0 Out IP 10.0.0.12.80 > 10.8.0.4.56488: Flags [S.], seq 2110509886, ack 2134132329, win 31856, options [mss 1460,sackOK,TS val 600172027 ecr 1212035220,nop,wscale 7], length 0
02:22:32.631355 eth0 Out IP 10.0.0.12.80 > 10.8.0.4.56488: Flags [S.], seq 2110509886, ack 2134132329, win 31856, options [mss 1460,sackOK,TS val 600174064 ecr 1212035220,nop,wscale 7], length 0
02:22:32.642741 eth1 In IP 10.8.0.4.56488 > 10.0.0.12.80: Flags [S], seq 2134132328, win 32120, options [mss 1460,sackOK,TS val 1212038281 ecr 0,nop,wscale 7], length 0
02:22:32.642764 eth0 Out IP 10.0.0.12.80 > 10.8.0.4.56488: Flags [S.], seq 2110509886, ack 2134132329, win 31856, options [mss 1460,sackOK,TS val 600174076 ecr 1212035220,nop,wscale 7], length 0
02:22:36.663361 eth0 Out IP 10.0.0.12.80 > 10.8.0.4.56488: Flags [S.], seq 2110509886, ack 2134132329, win 31856, options [mss 1460,sackOK,TS val 600178096 ecr 1212035220,nop,wscale 7], length 0
02:22:36.674601 eth1 In IP 10.8.0.4.56488 > 10.0.0.12.80: Flags [S], seq 2134132328, win 32120, options [mss 1460,sackOK,TS val 1212042313 ecr 0,nop,wscale 7], length 0
02:22:36.674625 eth0 Out IP 10.0.0.12.80 > 10.8.0.4.56488: Flags [S.], seq 2110509886, ack 2134132329, win 31856, options [mss 1460,sackOK,TS val 600178107 ecr 1212035220,nop,wscale 7], length 0
02:22:45.111350 eth0 Out IP 10.0.0.12.80 > 10.8.0.4.56488: Flags [S.], seq 2110509886, ack 2134132329, win 31856, options [mss 1460,sackOK,TS val 600186544 ecr 1212035220,nop,wscale 7], length 0
02:23:01.495353 eth0 Out IP 10.0.0.12.80 > 10.8.0.4.56488: Flags [S.], seq 2110509886, ack 2134132329, win 31856, options [mss 1460,sackOK,TS val 600202928 ecr 1212035220,nop,wscale 7], length 0
上記の結果から、TCPの場合は、protocol state filteringが働いて、サーバーからのパケットの返信がクライアントに届いていないことが分かります。
検証3: rp_filterを変更し、なおかつprotocol state filteringを変更した構成
戻りのパケットがeth0に紐づいているVNIを経由する際にフィルタリングされているため、eth0側のVNIにおけるprotocol state filteringを明示的にdisabledにします。
[root@syasuda-client ~]# ping 10.0.0.12
PING 10.0.0.12 (10.0.0.12) 56(84) bytes of data.
64 bytes from 10.0.0.12: icmp_seq=1 ttl=56 time=2.02 ms
64 bytes from 10.0.0.12: icmp_seq=2 ttl=56 time=1.83 ms
64 bytes from 10.0.0.12: icmp_seq=3 ttl=56 time=1.78 ms
64 bytes from 10.0.0.12: icmp_seq=4 ttl=56 time=1.88 ms
64 bytes from 10.0.0.12: icmp_seq=5 ttl=56 time=1.98 ms
^C
--- 10.0.0.12 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4007ms
rtt min/avg/max/mdev = 1.779/1.897/2.022/0.091 ms
[root@syasuda-client ~]# curl 10.0.0.12
Hellow World!