firewalldとiproute2でポートフォワーディング


はじめに

特定のポートの通信を、特定のゲートウェイを通して行わせようと思います。

以前「nginxをminecraftのプロキシとして使う」という記事を書きました。
表に置くサーバーと、アプリケーションを動かすサーバーを分けるという話ですが、TCPレイヤーのプロキシを使用しているため、アプリケーション側から見ると接続元のIPアドレスがプロキシのものになってしまいます1
今回は、IPパケットをフォワーディングさせることで、この問題を回避してみます。

ネットワーク構成

minecraft: VM(VirtualBox), Minecraft(25565番ポート)を動かす想定のサーバー
gateway: VM(VirtualBox), clientからのパケットを直接受け取るサーバー
client: ホストマシン, Minecraftのクライアントを動かす

gatewayのネットワークアダプタはブリッジアダプタを使用して、ホストマシンと同じネットワークに置きます(DHCPなので、ルータの設定でgatewayのIPを192.168.0.101に固定しておきます)。
minecraft-gateway間は内部ネットワークで接続します。

設定内容

内部ネットワークの設定

gateway

nmcli c add type ethernet ifname enp0s8 con-name enp0s8
nmcli c m enp0s8 ipv4.method manual ipv4.addresses 10.0.0.101/24 connection.autoconnect true

minecraft

nmcli c add type ethernet ifname enp0s8 con-name enp0s8
nmcli c m enp0s8 ipv4.method manual ipv4.addresses 10.0.0.102/24 connection.autoconnect true

ポートフォワーディングの設定

gateway

# ip_forwardを有効化
echo 1 > /proc/sys/net/ipv4/ip_forward

firewall-cmd --direct --add-rule ipv4 nat PREROUTING 0 -p tcp --dport 25565 -j DNAT --to 10.0.0.102
firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 0 -p tcp --sport 25565 -j SNAT --to 192.168.0.101
firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -p tcp --dport 25565 -j ACCEPT

デフォルトではカーネルの設定でip_forwardが無効になっているので、有効にします。

(firewalld) PREROUTINGチェインで25565番ポート宛てのパケットの送り先を10.0.0.102に書き換えます。
(firewalld) FORWARDチェインで25565番ポート宛てのパケットが別のホストへ通過する許可設定を入れます。
(firewalld) POSTROUTINGチェインで送り元が25565番ポートのパケットの送り元を10.0.0.102に書き換えます。

minecraft

# 経路フィルタの設定
echo 2 > /proc/sys/net/ipv4/conf/enp0s8/rp_filter

firewall-cmd --direct --add-rule ipv4 mangle OUTPUT 0 -p tcp --sport 25565 -j MARK --set-mark 1

ip rule add fwmark 1 table 1
ip route add default via 10.0.0.101 dev enp0s8 table 1

経路フィルタに引っかかるようになるので、緩いフィルタ"2"に変更します。

(firewalld) OUTPUTチェインで、送り元が25565番ポートのパケットにマーク"1"を付けます。
(iproute2) マーク"1"を付けたパケットに適用するルートテーブルをテーブル"1"に変更し、テーブル"1"にgateway(10.0.0.101)を通過するルールを加えます。

以上の設定を入れることで、minecraftサーバーから見たclientのIPアドレスがgatewayのものではなく、本来のものとして通信することができるようになりました。

まとめ

  • ip_forwardとrp_filterの設定に気が付くのが遅れ結構な時間を無駄にした
  • Linuxでルーターを作れるようになった
  • デバッグでtcpdumpとかnetcatつかえるようになった
  • BungeeCordを使おう

こんなことをやろうとする人が他にいるかわかりませんが、とりあえずまとめました。
Minecraftに限った話だとBungeeCordを使うのが最善かと思います。


  1. Minecraftの場合はBungeeCord(Minecraftのプロキシアプリケーション)が独自のIP Forwardingでこれを解決しています。