SSH ポートフォワーディングで FTP 接続

CLIENT


はじめに

この記事に限ったことではないかもしれませんけど^^;;; この記事は特にくせがある感じのものです。少々強引な感じもありますので、参考程度にご利用くださいませ。

 

想定状況の確認

今回は SSH によるポートフォワーディング機能を利用して、FTP 接続を安全に行えるようにするのが目的です。

接続先のサーバには、すでに OpenSSLOpenSSH、そして wu-ftpd が組み込まれている状態です。そしてクライアント側は、Tera Term Pro + TTSSH を使用してポートフォワーディングを行い、SteedFTP という FTP クライアントを使用して接続する予定です。

 

また下記では、FTP-DATA が取り扱うファイル転送などの通信を データ転送 とあらわすことにします。

 

SSH とポートフォワーディング

SSH とは、Netscape 社が開発した SSL という暗号化技術を使って、安全にターミナルに接続できるようにするための仕組みです。今回は OpenSSH によって SSH を構成しているのですけど、SSH の機能の中ですこし面白いのがこの ”ポートフォワーディング” です。

ポートフォワーディングは、指定したポートを監視し、そのポートへのアクセスがあると、自動的に SSH へとそのデータを転送します。転送された側の SSH は、あらかじめ設定された情報を元に、そのデータを別のポートへ転送します。

これによって、SSL に対応していないものであっても、事実上、SSL によるデータの保護が実装できます。

 

これを実現するための前提条件としては、クライアント側には SSH ポートフォワーディングができるソフトウェア、サーバ側には ポートフォワーディングを受けることのできる SSH が必要となってきます。今回の場合は、クライアント側は Tera Term Pro + TTSSH、サーバ側は OpenSSH がそれらの役割を担うことになります。

 

今回は FTP のポートフォワーディングを行うことが目的です。

が、これを行うのは少しばかり工夫が必要のでした。それは FTP の接続方法が特殊である影響と、クライアント側が IP Masquerade 経由でインターネットへ接続していたこと、サーバ側はパケットフィルタによって保護されていたことなどによるものでした。

 

SSH ポートフォワーディングの仕組み

SSH のポートフォワーディングを実現するためには、クライアントとサーバの両者に SSH が存在している必要があります。

クライアントは SSH 接続の際に、サーバ側の SSH に対して、何番ポートをどこへ転送するかという情報を伝えます。それと同時に、自分側にもフォワーディングを行うために受け入れる準備を行います。クライアント側の SSH は新たに指定されたポートを開いて、そこに接続がなされるのを待ちます。

 

クライアント側の新たに開いたポートに接続がなされると、クライアントは自分自身の SSH に対してそのデータを転送します。転送されたデータを受け取った SSH はそれをサーバ側の SSH へ転送します。それを受け取ったサーバ側の SSH は、それをはじめに指定されていたポートへ転送します。

ここで注目するところは、クライアントとサーバ間の通信はすべて、保護された SSL 通信で行われていることになります。保護されていない通信はすべて自分自身で行われていますので、自分が信用できない場合を除けば安心です。

 

このような性質上、ポートフォワーディングされるソフトウェア側からみれば、クライアント側は自分自身のフォワーディング用に用意されたポートになります。サーバ側は、自分自身から接続要求がなされることになります。

 

FTP データ転送の仕組み

FTP がデータ転送をするとき、少し複雑なことがなされます。

まず、一般的に知られている FTP へ接続するためのポート番号は 21 番です。今回はこれを FTP ポートと呼ぶことにします。通常 FTP クライアントはこの FTP ポートへ接続を要求します。サーバからの接続が承認されると、クライアントはサーバと情報のやり取りをすることができます。

 

ただ、FTP が正常に振舞うには、これとはべつに、もうひとつの情報をやり取りするための接続が必要になってきます。

FTP は通常、はじめに確立したポートは、状況報告などの通信に使用します。そして、それとは別のファイル転送などを行うためにもうひとつ接続を確立します。これは、FTP サーバ側の FTP-DATA ポートを使用して実現します。これは通常は 20 番ポートです。以下ではこれを データ転送 と呼ぶことにします。

ここで重要となってくるのが、この接続はサーバ側からクライアントへ向けて接続の要求が出されるというところです。この場合、IP Masquerade などの機能を使っていると、サーバ側からの要求がゲートウェイまでしか届かないという状況に陥ります。そうなると、FTP には接続できるのに、いざ LIST コマンドや GET といった作業を行うと、エラーが発生してしまうということになります。

これは、IP Masquerade 側で解決策が用意されていて、FTP-DATA 接続を確立するにあたっての情報が FTP ポートに流れるというのを利用して、IP Masquerade 側が FTP ポートを監視、データ転送用の FTP-DATA 接続を正常に取り次げるようにするためのモジュールが存在しています。

 

これとは逆に、ファイル転送用のポートをクライアント側から要求する、”Passive Mode (パッシブモード)” という方法もあります。

これはサーバ側に PASV 命令を送ることによって実現できます。こうすることによって、データ転送用のコネクションは通常のサーバ側からではなく、クライアント側から要求されることになります。これでたとえ IP Masquerade に FTP 用のモジュールが組み込まれていなくても、正常に FTP 接続が行えるようになります。

 

FTP をフォワーディングする際の問題点

さて、実際に FTP を SSH フォワーディングしようと思うのですが、ここで解決しなくてはならない問題があります。それは、ファイル転送のためのポートをどうするかという問題です。

FTP ポートのほうは簡単です。ポートフォワーディングの設定をする必要のあるクライアント側が、すでに接続先の FTP ポート番号をあらかじめ知っているため、適切な設定ができるからです。

 

ところが、FTP-DATA ポートの方はそうはいきません。なぜならこの接続は、FTP サーバとの通信の途中で決定されるからです。通常は片側が FTP-DATA ポートなのでいいのですが、もう一方がそのときに空いていたポート番号というのが厄介どころです。

IP Masquerade は通常の FTP の場合、FTP ポートを監視して、FTP-DATA の片側のポートが決まるのを観察してるのですが、SSL によって保護されてしまっていては、観察しろといっても無理があります。しかも肝心な片側のポート番号が、クライアント側から命じられたポート番号であっては、制御しようにも難しいところがあります。

FTP-DATA の方は暗号化しなくてもいいという場合でも無理があります。なぜなら、サーバ側から見ると、接続しているのはサーバ自分自身です。そうなると、サーバは FTP-DATA 接続を自分自身と行おうとします。FTP-DATA の受け入れ準備が整っているのは、サーバ自身ではなくクライアント側であるので、正常に接続を確立することはできません。

 

そこで、FTP フォワーディングするときには ”Passive Mode” を使用するのがよさそうです。

Passive Mode の場合、ファイル通信用のポートは両側ともそのときに決まってしまいますが、幸いクライアント側から要求が再送されますので、SSL で保護しなくてもいいのであれば、すぐに使用することができるようになります。

特にファイルの内容まで保護する必要がなければ、FTP クライアントで PASV コマンドを発行すれば終わりです。逆に保護したい場合には、その時々によって変わるポート番号の通信を、なんとかしてクライアント側から SSH フォワーディングを通過させる必要があります。

 

FTP データ転送を保護する

現在の環境下でデータ転送を保護するには、何とかしてデータ転送が開始される前に SSH ポートフォワーディングをデータ転送用に開始しなくてはなりません。

データ転送用に使われるポート番号はその時々によって不定ですが、Passive Mode の場合、これをある程度制御することができます。ただし、クライアントソフトの都合に大きく左右されますので、かならずしもデータ転送までを SSL で保護できるとは限りませんので注意してください。

 

まずは、サーバ側の微調整です。

今回は Passive Mode 用に使われるポート番号の範囲を制限して、それらすべてをあらかじめ SSH でフォワーディング設定しておくという方法をとります。ポート番号の制限という作業を行いますので、データ転送の SSL 保護を考えていなくても、ファイアーウォールが存在しているときにもホールを空ける数を調整できるという利点もあります。

なお、クライアント側が Passive モード時にサーバの指示されたとおりの IP アドレスへ接続しようとするような場合、今回の方法ではデータ転送までは SSL 保護できませんので、特に FTP サーバを微調整する必要はありません。その場合、下記の FTP 本体のフォワーディング設定のみを行います。

 

まず、Passive Mode 用のポート範囲の制限です。

これには wu-ftpd のソースファイルをすこし修正して、再コンパイルする必要があります。編集するソースファイルは次の2つです。

  • ftpd.c
  • routevector.c

wu-ftpd-2.6.1/src/ftpd.c の中に、int passive_port_min = -1 と int passive_port_max = -1 という記述があると思います。ここを変更して、制限したいポートの範囲を調整します。今回は次のようにして、22000 から 22004 までの範囲に制限することにしました。

int passive_port_min = 22000;

int passive_port_max = 22004;

こうするとサーバ側が受け入れるデータ転送用のポート範囲が 22000, 22001, 22002, 22003, 22004 の5個に制限されますので、同時に何人の人がこのサーバへ SSL 接続するかによって適度に調節する必要があります。ただし、あとでこれらすべてを SSH フォワーディング設定しますので控えめに。

同様に wu-ftpd-2.6.1/src/routevector.c の中の checkports(void) 関数内の方も書き換えます。

passive_port_min = 22000;

passive_port_max = 22004;

また、Passive Mode の場合、接続に使用するポート番号のほかに IP アドレスもサーバから指定されるようです。一部のクライアントはこれを無視するものもあるようですけど、通常はちゃんとこちらも考慮されますので、この指定の部分も localhost、すなわち 127.0.0.1 を返すようにする必要があります。

これは /src/ftpd.c の中の void passive() 関数内で、pasv_addr = ctrl_addr; の行を次のような感じにすればよさそうです。

#define TO_IN_ADDR(ad1, ad2, ad3, ad4) htonl((ad1<<24)|(ad2<<16)|(ad3<<8)|ad4)

bzero(&pasv_addr, sizeof(struct sockaddr_in));

pasv_addr.sin_family = AF_INET;

pasv_addr.sin_addr.s_addr = TO_IN_ADDR(127, 0, 0, 1);

 

では、wu-ftpd をコンパイルしてインストールします。

./configure

 

make

make install

 

これで Passive Mode の範囲が 22000 から 22004 までに制限され、接続先の IP アドレスとして localhost を返す in.ftpd が出来上がりました。

すでに in.ftpd が使用されるように /etc/inetd.conf で設定されていれば問題ないですけど、そうでない場合は /etc/inetd.conf の中に、ftp stream tcp nowait root /usr/sbin/tcpd in.ftpd -l -a などのような記述をいれて kill -HUP `cat /var/run/inetd.pid` として INETD を再起動しておきましょう。

 

これでサーバ準備は完成です。あとはクライアント側の設定です。

クライアント側では Tera Term Pro を起動して、[Setup] → [SSH Forwarding...] を選択します。そして [Add...] ボタンを押して Passive Mode で使用するポートすべてを登録します。

Forward local port: 22000
to remote machine xxxxxxxxxx port 22000

クライアント側のポート ( Local Port ) とサーバ側のポート ( Remote Machine Port ) は同一のポート番号に設定します。Remote Machine とは、接続先のサーバコンピュータ名です。

このような設定を、開いたポートの分だけ設定します。今回の場合は 22000 から 22004 の5個までですね。それらの登録が完了したら Tera Term でサーバ側の SSH に接続すれば SSH フォワーディングの準備は完了です。

また、これとは別に FTP 本体へフォワードするためのポートも用意します。

Forward local port: 21
to remote machine xxxxxxxxxx port 21

こちらは別に Local Port と Remote Port が同一の番号である必要はありません。Local Port はクライアント側で使用していないポート番号を指定する必要がありますので、もしクライアント側でも FTP サービスが稼動しているような場合にはずらす必要が出てくるでしょう。Remote Machine 側のポート番号は、サーバ側が提供している FTP のポート番号です。

 

あとは FTP クライアントによる接続です。FTP クライアントで接続するとき、設定がいつもと違うので気をつけてください。

接続先のサーバは localhost となります。ポート番号も FTP 本体へフォワードするように設定した SSH フォワーディングの Local port を指定します。そして、データ転送を Passive Mode で行うように設定します。

これであとは接続すればまったく普通に FTP を利用できると思います。