LoginSignup
2
2

More than 3 years have passed since last update.

試して学ぶiptablse、ポートフォワード

Last updated at Posted at 2019-12-28

iptablesでポートフォワードを試してみたいと思います。

手元で試したいのでちょっと構成は特殊ですが以下です。

image.png

  • LAN(192.168.0.0/24)内にスマホとノートPCがあります。
  • ノートPC上にはwebサーバーをたて、4000番ポートで待ち受けさせます。
  • 図の簡略化のためLAN内のルーターは省略しています。

達成したいことはスマホのブラウザからノートPC(192.168.0.9)にアクセスした際に、
4000番ポートのサーバに応答させることです。

TODO

パケットの流れを下図でおさらいしながらTODOを洗い出します。
参考:Iptablesチュートリアル 1.2.2 Chapter 6.1

スマホブラウザのGETリクエストのパケットはDestination IPが192.168.0.9、Destination Portが80で、図の「NETWORK」から流れてきます。
サーバーは図の「Local Process」です。

よって、以下を実施すればリクエストのパケットはサーバーに到達できます。

  1. 図の「nat PREROUTING」でDestination IPを127.0.0.1に、Destination Portを4000に書き変える
    ※宛先がローカルホストのため、Routing Decisionでパケットは図の「INPUT」の流れに振り分けられます。
  2. 図の「filter INPUT」でそのパケットの通過を許可する

検証

初期状態は以下です。

# iptables -L        
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

デフォルトポリシーの設定

ホワイトリスト方式にします。

# iptables -P INPUT DROP
# iptables -P FORWARD DROP

ノートPC上のWEBサーバーへのアクセスを許可

TODOの順序と逆になりますが、まずノートPCのブラウザでサーバにアクセスできるようにします。

# iptables -A INPUT -d 127.0.0.1 -p tcp --dport 4000 -j ACCEPT
# iptables -A INPUT -s 127.0.0.1 -p tcp --sport 4000 -j ACCEPT

ローカルなのでややこしいですが、設定とパケットは以下のように対応します

# iptables -A INPUT -d 127.0.0.1/32 -p tcp -m tcp --dport 4000 -j ACCEPT

上記がブラウザからサーバーへ向かうパケットを許可

# iptables -A INPUT -s 127.0.0.1/32 -p tcp -m tcp --sport 4000 -j ACCEPT

上記がサーバーからブラウザへ向かうパケットを許可

スマホからのhttpアクセスをノートPC上のサーバーへ振る

スマホ(192.168.0.2)からのリクエストのdesinationをNAPT(Network Address Port Translation)します。

# iptables -t nat -A PREROUTING -s 192.168.0.2 -p tcp --dport 80 -j DNAT --to-destination 127.0.0.1:4000

LAN内のスマホ以外からもアクセスさせるには以下のようにします。

# iptables -t nat -A PREROUTING ! -s 192.168.0.9 -p tcp --dport 80 -j DNAT --to-destination 127.0.0.1:4000

DNATターゲットを使うことでDestination IPとDestination Portの書き変えを行っています。





上記で動きそうですが動きませんでした。

外部からlocalhostへはデフォルトでは繋がらないようです。
localhostは外界から隔絶されているべきだからでしょう。

今回は手元で検証するためなので設定を変更します。

# sysctl -w net.ipv4.conf.eth0.route_localnet=1

※eth0はスマホからのパケットが通るNICの名前に読み替えること

これでアクセスできました!

「サーバーからの応答パケットのSNATをする必要はないのか?」という疑問をもちましたか?僕は持ちました。
結論は必要ありません。DNAT, SNATは一方向の変換を定義してやれば逆方向は自動でおこないます。
※参考: DNATターゲット

設定の確認

最終的な設定は以下です。

root@X1-Carbon-6th:~# iptables-save 
# Generated by iptables-save v1.6.1 on Sat Dec 28 14:15:30 2019
*nat
:PREROUTING ACCEPT [167:28771]
:INPUT ACCEPT [10:624]
:OUTPUT ACCEPT [314:29752]
:POSTROUTING ACCEPT [314:29752]
-A PREROUTING -s 192.168.0.2/32 -p tcp -m tcp --dport 80 -j DNAT --to-destination 127.0.0.1:4000
COMMIT
# Completed on Sat Dec 28 14:15:30 2019
# Generated by iptables-save v1.6.1 on Sat Dec 28 14:15:30 2019
*filter
:INPUT DROP [3377:278628]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [3560:414379]
-A INPUT -d 127.0.0.1/32 -p tcp -m tcp --dport 4000 -j ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --sport 4000 -j ACCEPT
COMMIT
# Completed on Sat Dec 28 14:15:30 2019
root@X1-Carbon-6th:~# sysctl -n net.ipv4.conf.enx7cc3a186ea62.route_localnet 
1 

片付け

片付けるときは以下に気をつけてください。

  • table毎に-Fオプションでルールを消すこと、ポリシーを元に戻すこと
  • 今回の特殊対応した設定をsysctlで戻すこと
# iptables -F && iptables -F -t nat
# iptables -P INPUT ACCEPT && iptables -P FORWARD ACCEPT
# sysctl -w net.ipv4.conf.enx7cc3a186ea62.route_localnet=0

まとめ

手元の環境でポートフォワードを試しました。
パケットの流れの図がとても優秀で、見ながら考えれば十分に設定ができることを確認しました。

「いいね」よろしくお願いします。:wink:

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2