佐藤です。 Hiroo Ono (小野寛生) <hiroo.ono+free...@gmail.com> wrote in <cantk6sgbfq8abvpazrlm_kptk_hcyvm-n0waad7jtfco4_2...@mail.gmail.com>:
hi> 2015年3月31日 1:30 <zen-freebsd-us...@suzuki.que.ne.jp>: hi> > 鈴木@葛飾区です。 hi> > なんか、最初のご質問を私読み違えてますね。。。リモートへの転送と大変な hi> > 勘違いで。。 hi> > hi> > fwd 127.0.0.1,2222 なのでローカルへの転送なのでnatを使うまでもなくルー hi> > ルにマッチすれば2222に転送されるはずですね。。。 hi> hi> 私もそう思ってはじめはコメントするのを控えたのですが、「BSDカーネルの hi> 設計と実装」13.4節に hi> “ホストが複数のアドレスを持っている場合、パケットはその送信先がこれら hi> のどれかに一致すれば受け入れられる。” hi> とありますので、127.0.0.1:2222 に届いたけれども、パケットの宛先アドレ hi> スとポート番号を見て hi> 192.168.11.3:22 宛のパケットという処理がされているのではないかと思いま hi> す。 hi> ということで、パケットを書き換える NAPT が必要という指摘は正しいはずで hi> す。 hi> よくわかっていませんが。 このケースはローカルへの転送ですので、NAPT は必要ありません。 次の条件 - 127.0.0.1:2222 で listen している sshd と、 192.168.11.3:22 で listen している sshd が、それぞれ 同一のホスト (以降ホスト B と呼びます) に存在している - ホスト B の IPFW の fwd ルールで、192.168.11.3:22 宛のパケットが 127.0.0.1:2222 に転送される が満たされる場合、別のホスト 192.168.11.2 (以降ホスト A と 呼びます) からの TCP 接続要求は、次のような動作になります。 1. 始点 192.168.11.2:E, 終点 192.168.11.3:22 の TCP SYN が A から B に送られる。(E は ephemeral port) 2. IPFW がホスト B 上で 1. のパケットを 127.0.0.1:2222 に転送する。 この時、fwd ルールは、パケットの始点・終点アドレスを書き換えないため、 実際には 127.0.0.1:2222 に送られるにも関わらず、 ホスト B のネットワークスタックが socket レベルで認識する 終点アドレスは 192.168.11.3:22 のままです。 3. 2222 ポートで listen している sshd は、パケットを受け取って accept(2) をコールし、接続用の新しい socket を生成する。 この受け取ったパケットは、192.168.11.2:E -> 192.168.11.3:22 という 始点・終点アドレスとして解釈されるため、ホスト B からの TCP SYN+ACK の返送は、逆転して 192.168.11.3:22 -> 192.168.11.2:E に なります。 つまり、接続用の新しい socket には、ピアの始点として 127.0.0.1:2222 ではなく、192.168.11.3:22 が設定されます。 したがって、実際にパケットは 127.0.0.1:2222 に転送されているにも関わらず、 - A->B 方向の通信は 192.168.11.2:E -> 192.168.11.3:22 - B->A 方向の通信は 192.168.11.3:22 -> 192.168.11.2:E というアドレスにパケットが流れているように見えることになり、 アプリケーションからは、転送の事実は見えません。 sshd などのデーモンは accept した時点で接続用の socket から 通信相手のアドレス・ポート番号を取得しますが、 得られるピアの始点・終点には、127.0.0.1:2222 が現れないということです。 なので、2222/tcp と 22/tcp で待ち受けている 2 つの sshd がホスト B に あって、始点アドレスを条件に IPFW fwd で振り分けた場合、 外からは、どちらも 22/tcp に接続しているように見えます。 127.0.0.1:2222 で待ち受けているのに、192.168.11.3:22 から通信が 行なわれているように動作するのは奇妙な話のように思えますが、 listen しているアドレスと、accept の時の終点アドレスが 異なっているという状態は、特別なものではありません。 たとえばデーモンが INADDR_ANY (0.0.0.0) で listen している場合、 accept して生成される通信用 socket のピア始点アドレスは 当然ながら 0.0.0.0 ではなく、接続してきた相手のアドレスが使われます。 それとまったく同じです。 Tetsuya Ito <chalt...@agate.plala.or.jp> wrote in <20150331212326.2783.a7d5a...@agate.plala.or.jp>: ch> 結果を纏めますと、 ch> ch> add 1001 pass tcp from any to any established ch> add 1002 fwd 127.0.0.1,2222 tcp from not <特定IP> to me 22 ch> ch> ⇒ 先にestablishedがある場合はNG (22/tcpに接続される) ch> ch> add 1001 fwd 127.0.0.1,2222 tcp from not <特定IP> to me 22 ch> add 1002 pass tcp from any to any established ch> ch> ⇒ 想定通り特定IP以外は2222/tcpに接続される。 ch> ch> という結果となりました。 ch> ch> ただ、ローカルネットの接続まで拒否されてしまうので、ちょっと困ってます。 ch> ローカルネット接続のpassルールをfwdの前に設定するしかないですかね...。 established が先にあると、TCP の最初のパケットだけ 127.0.0.1:2222 に 転送されて、それ以降は 192.168.11.3:22 に送られてしまうため、 動作しないのだと思います。 ローカルネットの接続が拒否される、というのが具体的に 何を指しているのかがよく分からないのですが、 たとえばホスト B 上で "ssh 127.0.0.1" とやった時に 22/tcp ではなく 2222/tcp に接続されてしまうのが困るという話であれば、 to me ではなく to 192.168.11.3 と fwd を限定すれば良いように思います。 -- Hiroki
pgp0rZx7A7ZIM.pgp
Description: PGP signature