と、分からないかもしれないネタはこの辺にして、「telnet があれば、サーバ間でファイルの転送ができる(前編)」と題して FTP (File Transfer Protocol) の仕様を確認するコラム。
前置き、PASVコマンド
FTPというと、通常のPORTコマンドを使うやり取りを初めて理解したときは驚いた。
「PORTコマンドの発行を受け付けたサーバは、接続元ポートTCP/20 でクライアントにむけてTCPセッションを張りに来る。」
そうやって接続されたセッションがデータ転送ポートとして、ファイルリストのテキストデータや、バイナリデータの転送に使用される。
嘘やん、そんなのこちらポート空けてないのにどうすんの?って思う節があるかもしれないが、最近のファイアウォールやルータはその辺をヨロシクやってくれて、意識しなくてよいようになっている。
しかしそうではないルータの下にいるFTPクライアントの為に、PASVを使うという手順がある。
FTPサーバがPASVコマンドを受け付けると、任意のポートでLISTEN のTCP状態を取り、クライアントに通知します。
[PASV] → [227 Entering Passive Mode (192,168,10,15,239,11)]
カッコ内がカンマ区切りで、IPアドレス・待ち受けポートです。このメッセージからは「IPアドレス:192.168.10.15、ポート:61195」 でLISTENしますよ、と言うこと。ちなみに 61195 は 「239 * 256 + 11」 で計算します。
PASVに割りこんだらどうなるの?
PASVでポートの通知を受けたFTPのクライアントは、当然LISTENしているポートにTCPセッションを張りに行き、データはこのポートから送信されます。
と、ここでPASVで教えてもらったポートに telnet で接続するとどうなるか試した(※実験はPASVも telnet で発行しました。)ら、ちゃんとセッションが張れる。
そのまま最初に接続したコマンド用のセッションで、LISTなど発行すればPASVで張ったほうのセッションからリストデータが、RETRをすればファイルの中身が流れてくるといった具合。
基本的に接続元の制限などない模様なので、これはこれで危なっかしいとも思えるが、もうちょっと突っ込んで考えてみる。
PORT と PASV の組み合わせで、と思ってRFCを参照する
使わないから意識していなかったが、FTPはサーバ同士のデータ転送という役割を与えられたプロトコルでもある、と言うのを形だけ知っていた。
上の割り込み実験から、「PASV で待ちうけ、PORTで接続」 とすればサーバ間の転送ができるんじゃないかと思って、RFCを読んでみた。
RFC:959(原文)(日本語訳)
すると、「5.2. CONNECTIONS」 の所にしっかり書いてあった、今でこそ一般的ではないやり方だけど、RFCでは一番シンプルなFTPの使い方としてサーバ間のデータ転送が紹介されている方法だった。
telnet2本張って サーバ間のデータ転送
コントロールはクライアントから、データの転送は2台のサーバ間で。
サーバA(SV-A)からサーバB(SV-B)にファイルを転送したい場合、ざっとこういう手順で達成できるはず。図が崩れてたらごめんなさい、Firefoxだと一応きれい。
┌──────┐ ┌──────┐ | コントロールするクライアントから、両方にtelnet でFTPログイン |
LISTEN | SV-B にPASVコマンドを発行、ポートをLISTENさせる |
LISTEN | SV-Bが待ち受け中なので、SV-AへPORTコマンドを送る。送信内容はSV-BのIPアドレスとポート すると、SV-A と SV-B の間でFTPデータ用のセッションが確立するはず |
┌──────┐→data→┌──────┐ | 後編作成後に認識間違いを修正。図も修正。 初版ではここの解釈に嘘があった、STORで待ち構え、RETRで送るというオペレーションが必要ということだ。 (初版)データコネクションが確立したら、STORコマンドでファイルの転送が行えるはず。 RFCではSV-B側でRETRコマンドが必要とあったが、この辺がよく分からない。 |
さて、手元に実験できるサーバがないので今度試してみよう。
後編につづく