LuaSocket FTPが常にタイムアウトする
-
03-07-2019 - |
質問
LuaSocket で成功しましたTCP機能ですが、FTPモジュールに問題があります。 (小さな)ファイルを取得しようとすると、常にタイムアウトが発生します。 Firefoxまたはパッシブモードのftp(Ubuntu Dapper Linux)を使用して、ファイルを問題なくダウンロードできます。
LuaSocketがパッシブFTPを使用する必要があるのではないかと考えましたが、デフォルトでそれを行うように見えることがわかりました。 FTP経由で取得しようとしているファイルには、マシン上の他のプログラムを介してパッシブFTPでアクセスできますが、アクティブモードではアクセスできません。 「ハッキング」に関する話を見つけました。 LuaSocketへのパッシブモードのサポート、およびその議論は、後のバージョンがパッシブモードの使用を停止したことを示唆していますが、私のバージョンはとにかくパッシブを使用しているようです(2.0.1を使用しています;最新のものは2.0.2であり、関連する変更はないようです私のユースケース)。その投稿が私の状況にどのように関連するかについて少し混乱していますが、それは、一部は非常に古く、LuaSocketのソースはその議論のコードとほとんど似ていないからです)。
コードをこれに要約しました:
local ftp = require "socket.ftp"
ftp.TIMEOUT = 10
print(ftp.get("ftp://ftp.us.dell.com/app/dpart.txt"))
これにより、タイムアウトが発生します。 Linuxでは strace
で実行しました(Solarisでは ptrace
と同じです)。これは要約された転写です:
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
fcntl64(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
recv(3, "230-Welcome to the Dell FTP site."..., 8192, 0) = 971
send(3, "pasv\r\n", 6, 0) = 6
recv(3, 0x8089a58, 8192, 0) = -1 EAGAIN (Resource temporarily unavailable)
select(4, [3], NULL, NULL, {9, 999934}) = 0 (Timeout)
接続しようとした別のサイトがありますが、ここには投稿できないパスワードがありますが、その場合、結果はわずかに異なりました...上記のようなトレースを取得しましたが、 select()
最後に成功し、これ:
recv(3, "227 Entering Passive Mode (123,456,789,0,12,34)\r\n", 8192, 0) = 49
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 4
fcntl64(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
connect(4, {sa_family=AF_INET, sin_port=htons(12345), sin_addr=inet_addr("123.456.789.0")}, 16) = -1 EINPROGRESS (Operation now in progress)
select(5, [4], [4], NULL, {9, 999694}) = 0 (Timeout)
これを私の「ftp」のトレースと比較してください。パッシブモードのプログラム(正常に動作しますが、LuaSocketのようにソケットを非ブロックに設定しないことに注意してください):
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 6
write(5, "PASV\r\n", 6) = 6
read(3, "227 Entering Passive Mode (123,456,789,0,12,34)\r\n", 1024) = 51
connect(6, {sa_family=AF_INET, sin_port=htons(12345), sin_addr=inet_addr("123.456.789.0")}, 16) = 0
だから、これら2つの異なるFTPサイトに対してLuaSocketを試してみましたが、異なるが同様の障害がありました。また、アクティブFTPが動作する別のマシンから試してみましたが、幸運はありませんでした(おそらくLuaSocketは常にパッシブモードを使用しているため、 socket / ftp.luaでソースを読み取ることでわかります)
)。
では、ここの誰かがLuaSocketを2ライナーにすることができます。私のマシンでは、DellのサイトへのアクティブFTPが機能しないことに注意してください(接続できますが、 ls
を行うとすぐに切断されます)。LuaSocketが機能するようになったら、アクティブFTP別のプログラムからDellのサイトにアクセスすると、マシンで動作します。
解決
うーん。問題は、LuaSocketが「pasv」を使用しているように見えることです。小文字で。回避策を見つけようとしています。
うーん。いいえ、それは非常にエレガントに溶接されて閉じられています。最も簡単な方法は、おそらくLUA_PATHの以前のパスの階層内の同等の場所にその特定のファイルをコピーすることです。つまり、(通常)ファイルのローカルコピーを作成します。 path / to / your / project / socket / ftp.lua
。
次にローカルファイルを編集します:
- self.try(self.tp:command("user", user or USER))
+ self.try(self.tp:command("USER", user or USER))
- self.try(self.tp:command("pass", password or PASSWORD))
+ self.try(self.tp:command("PASS", password or PASSWORD))
- self.try(self.tp:command("pasv"))
+ self.try(self.tp:command("PASV"))
- self.try(self.tp:command("port", arg))
+ self.try(self.tp:command("PORT", arg))
- local command = sendt.command or "stor"
+ local command = sendt.command or "STOR"
- self.try(self.tp:command("cwd", dir))
+ self.try(self.tp:command("CWD", dir))
- self.try(self.tp:command("type", type))
+ self.try(self.tp:command("TYPE", type))
- self.try(self.tp:command("quit"))
+ self.try(self.tp:command("QUIT"))
逆に、getfenv、getmetatableなどを使用したnavelnaut遠征は、価値があるとは思えませんでした。私はそれを設計の重大な問題だと考えています。 (LuaSocketの)
RFC0959 はすべて大文字のコマンドを使用することに注意してください。 (おそらく7ビットASCII時代のものだからです。)
他のヒント
サーバーは、コマンドが大文字と小文字を区別しないことを示すFTP仕様に従わないことに注意してください。 RFC959のセクション5.3を参照してください"コマンドコードは4文字以下のアルファベット文字です。 大文字と小文字のアルファベット文字が処理されます 同様に。したがって、次のいずれかが 検索コマンド: RETR Retr retr ReTr rETr"
この問題は修正され、質問と最初の回答が非常に役立ちました。
LuasocketはRFC 959に準拠しています(ここでの最初のコメントは大文字では正しくありません。RFC959セクション5.2を参照)
少なくともMicrosoft FTPサーバーは準拠していません。他にもあるかもしれません。
解決策はpasvをPASVに変更することで、大文字と小文字を区別するコマンドサーバーの回避策です。詳細はLuaのメーリングリストに記載されており、アーカイブは数日中にWebからアクセスできるようになります。
(ftp.luaの59行目を編集)