tanke25616429のアウトプット

IT技術の基本を勉強したことをアウトプットします。Linux、Kubernetes、クラウド中心です。百番煎じくらいだけど誰かの役に立てばそれはそれでうれしい。

LinuxにおけるIPフォワーディング

概要

LinuxにはIPパケットをフォワーディングする機能が具備されている。IPフォワーディングはあるネットワークから受け取ったパケットを別のネットワークに転送する技術である。言い換えると、2つのNICの間でパケットを転送する技術である。これにより、パケットが異なるネットワークの間を往き来できるようになる*1

LinuxでIPフォワードを有効にするには、カーネルパラメータ net.ipv4.ip_forwardの値を1にする必要がある(設定方法は過去エントリを参照 カーネルパラメータの設定方法(CentOS 8) - Knのアウトプット)。 カーネルパラメータを設定した段階では2つのNIC間でパケットが転送できるようになっただけで、適切な通信が行われるようになったわけではない。実際にフォワーディングされるためにはルーティングテーブルを適切に設定する必要がある。

設定例

サーバーA、B、Cの3台があり、Bに対しフォワーディングの設定を行う。 Bは2つのネットワーク、192.168.0.0/24192.168.122.0/24に所属している。

[root@nuc-centos8 ~]# ip a
(略)
4: wlp0s20f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 0c:7a:15:da:07:37 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.14/24 brd 192.168.0.255 scope global dynamic noprefixroute wlp0s20f3
(略)
5: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 52:54:00:9c:81:ac brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
(略)

サーバAは192.168.0.0/24のみに所属している。

[root@virtualbox-centos7 ~]# ip a
(略)
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:08:35:9c brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.92/24 brd 192.168.0.255 scope global noprefixroute enp0s8
(略)

サーバCは192.168.122.0/24のみに所属している。

[root@kvm-centos8 ~]# ip a
(略)
2: ens2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:34:01:09 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.100/24 brd 192.168.122.255 scope global noprefixroute ens2
(略)

サーバAからサーバCへpingを打つ。このときサーバBでIPフォワーディングが有効になっており、ルーティングテーブルが設定されていればpingは到達する。 なお、サーバAからサーバBにパケットが飛ぶようにするため、サーバAのデフォルトゲートウェイはサーバBのIPアドレスにしてある。

[root@virtualbox-centos7 ~]# nmcli con show enp0s8
(略)
ipv4.addresses:                         192.168.0.92/24
ipv4.gateway:                           192.168.0.14
(略)

サーバBではすでにIPフォワーディングが有効( net.ipv4.ip_forward = 1)で、ルーティングテーブルも設定済みである*2

[root@nuc-centos8 ~]# sysctl -a | grep net.ipv4.ip.forward
net.ipv4.ip_forward = 1
net.ipv4.ip_forward_update_priority = 1
net.ipv4.ip_forward_use_pmtu = 0
[root@nuc-centos8 ~]# ip r
default via 192.168.0.1 dev wlp0s20f3 proto dhcp metric 600
192.168.0.0/24 dev wlp0s20f3 proto kernel scope link src 192.168.0.100 metric 600
192.168.0.0/24 dev wlp0s20f3 proto kernel scope link src 192.168.0.14 metric 600
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1

サーバAからpingを打つ。応答が返ってきていることがわかる。

[root@virtualbox-centos7 ~]# ping 192.168.122.100
PING 192.168.122.100 (192.168.122.100) 56(84) bytes of data.
64 bytes from 192.168.122.100: icmp_seq=1 ttl=63 time=106 ms
64 bytes from 192.168.122.100: icmp_seq=2 ttl=63 time=22.9 ms
64 bytes from 192.168.122.100: icmp_seq=3 ttl=63 time=41.1 ms
(略)

pingを打ちっぱなしのままサーバCでtcpdumpを使いパケットを監視してみると、ICMPのrequestが飛んできている。

[root@kvm-centos8 ~]# tcpdump -i any src host 192.168.0.92 -n
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
11:07:47.686403 IP 192.168.0.92 > 192.168.122.100: ICMP echo request, id 2747, seq 57, length 64
11:07:48.710472 IP 192.168.0.92 > 192.168.122.100: ICMP echo request, id 2747, seq 58, length 64
11:07:49.734488 IP 192.168.0.92 > 192.168.122.100: ICMP echo request, id 2747, seq 59, length 64
11:07:50.656000 IP 192.168.0.92 > 192.168.122.100: ICMP echo request, id 2747, seq 60, length 64
(略)

pingtcpdumpを仕掛けたまま、サーバB上でIPフォワーディングを無効化してみる。一時的に無効化するにはファイル/proc/sys/net/ipv4/ip_forwardの値を直接0に書き換える。

[root@nuc-centos8 ~]# echo 0 > /proc/sys/net/ipv4/ip_forward

サーバAのping応答が止まる。

(略)
64 bytes from 192.168.122.100: icmp_seq=126 ttl=63 time=98.5 ms
64 bytes from 192.168.122.100: icmp_seq=127 ttl=63 time=117 ms
(ここで止まる)

サーバCでもtcpdumpの更新が止まる。

(略)
11:11:26.734165 IP 192.168.0.92 > 192.168.122.100: ICMP echo request, id 2748, seq 126, length 64
11:11:27.757086 IP 192.168.0.92 > 192.168.122.100: ICMP echo request, id 2748, seq 127, length 64
(ここで止まる)

サーバB上でIPフォワーディングを再び有効にするとpingの応答が返り、tcpdumpの更新が再開される(応答が返ってきている様子等は割愛する)。

[root@nuc-centos8 ~]# echo 1 > /proc/sys/net/ipv4/ip_forward

参考にしたもの

IPフォワード(IP Forward) | Linux技術者認定 LinuC | LPI-Japan

xtech.nikkei.com

*1:フォワーディングとルーティングは厳密には区別される。ルーティングは転送先の経路を選択すること、フォワーディングは実際に転送することである。ただし、ルーティングといった場合に経路選択と転送をまとめて呼ぶケースもあるので、文脈に応じて読み取る必要がある。

*2:192.168.0.100はネットワークデバイスNIC)wlp0s20f3に振ったセカンダリIPアドレスであり、今回の実験には関係ないので無視してよい。