telnet ですかー!?と、分からないかもしれないネタはこの辺にして、「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だと一応きれい。
┌──────┐ ┌──────┐ │ SV-A │ │ SV-B │ └──────┘ └──────┘ ↑ ↑ │ │ │telnet 21 │telnet 21 │ ┌──────┐ │ └←│ Ctrl │→┘ └──────┘
|
コントロールするクライアントから、両方にtelnet でFTPログイン |
LISTEN ┌──────┐ ┌──────┐ │ SV-A │ ★ SV-B │ └──────┘ └──────┘ │ ↑ │ │ │ │PASV │ ┌──────┐ │ └─│ Ctrl │→┘ └──────┘ |
SV-B にPASVコマンドを発行、ポートをLISTENさせる |
LISTEN ┌──────┐ ┌──────┐ │ SV-A →───→★ SV-B │ └──────┘ └──────┘ ↑ │ │ │ │PORT(SV-B) │ │ ┌──────┐ │ └←│ Ctrl │─┘ └──────┘ |
SV-Bが待ち受け中なので、SV-AへPORTコマンドを送る。送信内容はSV-BのIPアドレスとポート すると、SV-A と SV-B の間でFTPデータ用のセッションが確立するはず |
┌──────┐→data→┌──────┐ │ SV-A ====== SV-B │ └──────┘ └──────┘ ↑ ↑ │ │ │RETR(File) │STOR(File) │ ┌──────┐ │ └←│ Ctrl │→┘ └──────┘ |
後編作成後に認識間違いを修正。図も修正。 初版ではここの解釈に嘘があった、STORで待ち構え、RETRで送るというオペレーションが必要ということだ。 (初版)データコネクションが確立したら、STORコマンドでファイルの転送が行えるはず。 RFCではSV-B側でRETRコマンドが必要とあったが、この辺がよく分からない。 |
さて、手元に実験できるサーバがないので今度試してみよう。
後編につづく