はじめに
前の記事の構成を設定したあと、メインルーターでポート転送を設定していて、転送先のマシンがサイドルーターをゲートウェイにしている場合、ポート転送が効かなくなっているはずです。これはClashの振り分けが原因ではありません。ゲートウェイをサイドルーターにすると、メインルーターのポート転送が効かなくなります。
仕組み(長いので読み飛ばしてもOK)
ゲートウェイの役割は、要するにNATによるアドレス変換で、内部ネットワークの通信を外部へ転送することです。内部から外部への通信は必ずゲートウェイを通るため、各マシンには外部と通信するためのゲートウェイアドレスを設定する必要があります。
実装を単純化して考えると、ゲートウェイは自動のポート転送のようなものです。5タプルで一意に識別される各アクティブ接続について、内向きと外向きのポートを1組管理します。たとえば自分のマシンがGoogleのサーバーに接続し、ゲートウェイが管理するポートの組が(32384, 14122)なら、Google宛ての通信はすべてゲートウェイの32384番ポートへ送られ、そこから14122番ポート経由でGoogleへ転送されます。Googleからのパケットも逆向きに同じ転送を通ります。NATが1段だけとは限りません。回線にグローバルIPが割り当てられていなければ、自宅のゲートウェイの上流でもNATが行われます。最終的にGoogleと通信するゲートウェイは、必ずグローバルIPを持っています(インターネット上で通信できるのはグローバルIPを持つマシンだけだからです)。
サイドルーターもゲートウェイとして動作するため、NATを行います。つまり、自分のマシンと外部との通信は実際には2段のNATを通ります。
你的机器 <——> 旁路由(NAT) <——> 主路由(NAT) <——> 外部机器
メインルーターにポート転送を設定し、内部マシンのゲートウェイはサイドルーターにしている場合、グローバルIPから内部へアクセスすると、往路は次のようになります。
外部机器 ----> 主路由网关 ----> 你的机器
一方、復路は次のようになります。
你的机器 ----> 旁路由 ----> 主路由 ----> 外部机器
外部マシンが接続を開始した時点では、自分のマシンはメインルーターのゲートウェイとしか接続を確立していません。ところが返りの通信はサイドルーターへ送られます。サイドルーターにはその接続に対応するポートの組がないため、パケットを破棄してしまい、ポート転送が失敗します。
解決方法(ここだけ読めばOK)
解決策は簡単です。NATが2段あるので、ポート転送も2段に設定すればよいだけです。
- メインルーターで、サイドルーター宛てのポート転送を設定します。
- サイドルーターで、目的のマシン宛てのポート転送を設定します。
これで往路も復路も次の経路になり、接続が成立します。
你的机器 <——> 旁路由(NAT) <——> 主路由(NAT) <——> 外部机器
ポート転送の設定方法はシステムによって異なります。iKuaiとOpenWrtにはGUIがあるので、ここでは省略します。前の記事ではサイドルーターにDebianを使いましたが、次の方法はiptablesを使うシステム全般で利用できます。以下のコマンドでiptablesを設定します。例では転送先マシンを「内部」、ゲートウェイのマシンを「外部」と呼んでいます。
iptables -t nat -I PREROUTING -p tcp -d <外部 IP> --dport <外部端口> -j DNAT --to-destination <内部 IP>:<内部端口> iptables -t nat -I POSTROUTING -p tcp --dport <内部端口> -d <外部 IP> -j SNAT --to-source <内部 IP>
これでiptablesの設定ができます。
前の記事のclean.shにあるiptables -t nat -Fは、ユーザー定義のルーティングルールをすべて消去するため、転送も無効になります。実行後は、上のコマンドを追加で実行してください。
