あるホストから別のホストへ通信する際の通信先のホストのIPをiptablesで変換する方法を記載する。

送信先IPアドレスをiptablesで変えたい時

iptablesでの実現の仕方を書く前に、送信先IPアドレスをiptablesで変えたいのはどのような時か。例を2つあげたい。

グローバル経由でRedis Sentinelに接続する

プライベートLAN内でReplication + Sentinelを組んでいるとする。事情によりグローバルから接続する必要があるとする。Redis SentinelにMasterのIPアドレスを聞く(SENTINEL get-master-addr-by-name <master name>)と、Replicationの接続先に使っているプライベートIPが返ってくる。グローバルから接続したいのにプライベートIPでは接続できないので、プライベートIPを指定してもiptablesで自動的にパブリックIPに変換してもらいたい。

$ head -2 /etc/hosts
AAA.AAA.AAA.AAA    redis_private_ip
BBB.BBB.BBB.BBB    redis_public_ip

$ redis-cli -h AAA.AAA.AAA.AAA
# iptablesで自動的にAAA.AAA.AAA.AAAをBBB.BBB.BBB.BBBに変換して接続したい

Failoverした後の新サーバへ接続する

Active/Standbyでサーバが2台あるとする。ActiveサーバのIPをAAA.AAA.AAA.AAA、StandbyサーバのIPをBBB.BBB.BBB.BBBとする。何らかの方式でFailoverする。Failover時、IPアドレスAAA.AAA.AAA.AAAを指定して旧Activeサーバに接続しているアプリが自動で新Activeサーバへ接続する仕組みをiptablesで構築したい。
Failoverを検知したらiptablesを書き換えて、AAA.AAA.AAA.AAAに接続してもBBB.BBB.BBB.BBBに変換するスクリプトをcron等で動かす。

PREROUTING/POSTROUTING

送信先IPアドレスをiptablesで変える方法について調べると、ホスト間にある"ルータ"の役割を果たすサーバのiptablesへの設定方法がたくさんヒットする。
プライベートネットワークのコンピュータをインターネットへアクセス可能にしたり、内部ネットワークに存在するサーバを外部に公開するとき、ルータが送信元アドレス変換をおこなうSNATターゲット、送信先アドレス変換をおこなうDNATターゲットをiptablesで使って実現している。

iptablesでは送信元アドレスを変換するとき、ルールにPOSTROUTING、ターゲットにSNATを使う。

-A POSTROUTING -p tcp -d AAA.AAA.AAA.AAA -j SNAT --to-source BBB.BBB.BBB.BBB

送信先アドレスを変換するとき、ルールにPREROUTING、ターゲットにDNATを使う。

-A PREROUTING -p tcp -d AAA.AAA.AAA.AAA -j DNAT --to-destination BBB.BBB.BBB.BBB

NATとかNAPTはIPアドレスの枯渇問題に関連して出てきた技術なので、ルータが話に登場するのは自然だ。しかし、今回は単純にあるホストから別のホストへ通信する際の通信先のホストのIPを変換したいので、ルータは登場しない。したがってルータで使用するPREROUTING + DNATは使えない。

OUTPUT

通信元のホストのiptablesで使用するのはOUTPUTDNATとなる。PREROUTING/POSTROUTINGはパケットを"中継"するときに使用するルールなのでルータに使用するサーバのiptablesで設定する。中継ではなく単純にあるホストから別のホストへの送信先IPをiptablesで変換したいだけなのでOUTPUTルールを使用する。

-A OUTPUT -d AAA.AAA.AAA.AAA -j DNAT --to-destination BBB.BBB.BBB.BBB

参考
http://www.turbolinux.co.jp/products/server/11s/user_guide/x9664.html
https://serverfault.com/questions/124184/iptables-change-destination-ip-without-dnat