sshはすべてのデバイスで動作しますが、一部のデバイスではscpが「接続が閉じられました」エラーが発生します。

sshはすべてのデバイスで動作しますが、一部のデバイスではscpが「接続が閉じられました」エラーが発生します。

クイックバージョン:

ssh&scp私のデスクトップとラップトップで動作します。私のAndroid携帯電話ではtermuxはssh動作しますが、scp動作しません。この場合、「接続が終了しました」というエラーが発生します。


拡張バージョン

もともとこの質問をしたときに、Fedora Linuxボックスに接続されている間にAndroid携帯電話のtermuxでscpを実行しているときにこの問題が発生しました。sshあれこれ作業をしてデバッグ情報をたくさん提供していて混乱します。後で問題がtermuxとまったく関係がなく、すべてがOpenSSHバージョンに関連していることがわかりました。 。

機器:

  • デバイスA(コンピュータ):openssh.x86_64 8.7p1-3.fc35を実行するFedora 35
  • デバイスB(コンピュータ):openssh.x86_64 8.7p1-3.fc35を実行するFedora 35
  • デバイスC(電話):Androidのtermux(最初はopensshバージョン、おそらくv8.8以降をキャプチャできませんでした)

コンピュータAとBは基本的に同じsshd_configファイルを持ち、ファイルの内容は基本的に3台のコンピュータで同じです~/.ssh/config

質問:

A-> B、B-> A、C-> A、C-> B間のSSH接続はすべてうまく機能します。私はどのコンピュータからも電話に接続することに興味がなく、SSHDを設定したことがないので、そのシナリオをテストしませんでした。

ただし、sshを介してscpを実行すると、次のような状況が発生します。 A->BとB->Aは機能しますが、C->AとC->Bは次のエラーで失敗します。

$ scp -rp "[email protected]:/home/desktop-user/Pictures/test.jpg" .
scp: Connection closed
 

デバッグ:

  • SSHファイルの権限、所有権~/.ssh/config、設定などに関する広範な確認明らかな問題はありません。
  • AとBでSELinuxとファイアウォールを(一時的に)無効にしましたが、まだ同じ問題があります。
  • に基づいてこの投稿、デフォルト名を使用するようにカスタムid_rsa(およびid_rsa.pub)ファイルの名前を変更し、その~/.ssh/config定義を編集しました。お金を守ってください。
  • Cでファイルを受け取ったりインポートしたりする代わりに~からリモートでファイルをプッシュ/転送しようとしています。到着リモコン。お金を守ってください。
  • Cから始めて、すべてのパッケージが最新であることを確認します。お金を守ってください。
  • 詳細なデバッグ情報を提供するために、フラグをscp使用してCでコマンドを実行します。-vハッシュなどを編集して追加しました。ペーストビン。私が見た最も重要なことは、キーが承認されているようですが、最後の行に「debug1:終了ステータス127」と表示されていることです。オンライン結果は、scpホストシステムに存在しないように見えます。しかし、私の場合は存在します。だからまだ変化はありません。

ホストSSHDの設定

同様に、AとBの構成は基本的に同じです。

# grep -Pv '^\s*(#|$)' /etc/ssh/sshd_config
Include /etc/ssh/sshd_config.d/*.conf
Port 22
Ciphers [email protected],aes256-ctr
LoginGraceTime 1m
PermitRootLogin no
MaxAuthTries 4
MaxSessions 6
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding yes
PrintMotd no
UseDNS yes
AcceptEnv LANG LC_*
Subsystem   sftp    /usr/lib/openssh/sftp-server
Protocol 2
DenyUsers root docker-user
MACs [email protected],hmac-sha2-512,[email protected],hmac-sha2-256
KexAlgorithms diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256

答え1

エクスプレスバージョン(TL; DR)

修正する: 早く知りたい、最小限の内容でも読みたい方のための製品です。

知っている:

  1. これは実際にTermuxとは関係ありません。 OpenSSH 8.8+を使用するすべてのLinuxに影響を与えます。 OpenSSH 8.7p1を使用するFedora 35でもこの問題が発生しました。
  2. sftp緊急時には機能しますが、シンボリックリンクのコピーは異なる方法で処理されるため、代わりにスクリプトに入れないでscpください。を使用する方が良いですrsync

ディレクトリをリモートからローカルに繰り返しコピーします。

# deprecated / insecure (see CVE link below) but works
scp -O -rp -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"
 
# secure / recommended by openssh - also works
rsync -saLPz --port <port> -e ssh "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"

ローカルからリモートにディレクトリを繰り返しコピーします。

# deprecated / insecure (see CVE link below) but works
scp -O -rp -P <port> "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"
 
# secure / recommended by openssh - also works
rsync -saLPz --port <port> -e ssh "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"

これはマルチパスにも当てはまります。

# copy multiple paths
rsync -saLPz --port <port> -e ssh "<SRC_PATH_1>" "<SRC_PATH_2>" "<SRC_PATH_3>" "<user>@<host_ip>:<DST_PATH>"
 
# copy multiple paths from array
arrPaths=("<SRC_PATH_1>" "<SRC_PATH_2>" "<SRC_PATH_3>");
rsync -saLPz -e ssh "${arrPaths[@]}" "<user>@<host_ip>:<DST_PATH>"

根本原因

〜の後たくさんオンライン狩り私ついに答えを見つけましたここ- 初期の修正を探して何が起こったかを教えてくれたmanjaroフォーラムのユーザーzbeとcanyue980に感謝します。

canyue980引用:

助けてくれた皆さんに感謝します!上記のリンクで解決策を見つけました。

注:OpenSSH 8.8以降、scpユーティリティはデフォルトでSFTPプロトコルを使用します。レガシーSCPプロトコルを使用するには、-Oオプションが必要です。

-Oオプションを使用してください!

scp -O ファイル名 宛先ディレクトリ

もちろん、以下のように〜/ .zshrcにエイリアスを追加することもできます。

エイリアス scp="scp -O"

実際、私のコマンドは次から始まります。

scp -rp -P 1234 "[email protected]:/home/desktop-user/Pictures/test.jpg" .

到着する:

scp -rpO -P 1234 "[email protected]:/home/desktop-user/Pictures/test.jpg" .

それはチャンピオンのように動作します。これを開いたままにして、他の人に役立つことを願っています。


-Oのセキュリティ影響

使用するのに安全な意味-O(例:「ああ」、以前と同じようにゼロではない):リリースノートopenssh 8.8では、主なリスクは次のとおりです。

以前のバージョンのscp / rcpは、リモートシェルを介してリモートファイル名(「scpホスト:* .」など)のワイルドカード拡張を実行します。これに対する副作用は、scp(1)コマンドラインに含まれるファイル名にシェルメタ文字を二重引用符で囲む必要があることです。そうしないと、リモート側でシェルコマンドとして解釈される可能性があります。

私は個人的にこれが以前のコマンドに慣れていて、それを手動で実行したり、家庭のコンピュータで信頼できるスクリプトを介して実行している人にとっては大きな危険だとは思わない。ただし、リスク評価/ユースケースはさまざまです。特に、検証されていないスクリプトや信頼できないスクリプトを使用するビジネスシステムまたは設定の場合は、はい。これは一部のケースのようですRHEL 9はscpプロトコルを使用しなくなりました。、引用する:

SCPプロトコルは何十年も経っており、直接的な解決策がないいくつかのセキュリティリスクと問題があるため、このように変更しました。新しい問題がよく報告されます(CVE-2020-15778この記事を書いている時点では最新ですが、最後になるかどうかはわかりません。

上記のリリースノートとリンク、コメントからアーチスウィキ、完全に使用したくない意図のようです。SCP(例:プロトコル)は、(以下を参照)sftpなどの選択肢をサポートします。rsync会社の今後の計画は何か分からない。scp 注文するはい、特に短期的にはそうです。しかし、今後は使用されなくなる可能性が高くなります。


推奨代替

スクリプトで挿入 - 代替としてsftp使用すると、少なくともFedora 35から開始する必要があるホストの変更は不要であるため、挿入 - 交換が簡単になります。rsyncrsyncsftp

sftpsftp <user>@<host_ip>以下のコマンドは、以下を使用して接続できる限り機能します(この方法で接続すると「シェル」に入ります。ssh終了するには使用します)。それ以外の場合は、ホストシステムでこれを有効にする必要があります。 Fedora 35の場合、プロセスは次のとおりです。sftpexit

  1. sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.$(date +'%F_%T').bak
  2. sudo sed -Ei 's~^(Subsystem[ \t]+sftp[ \t]+)(/usr/lib/openssh/sftp-server)~#\1\2\n\1internal-sftp~g' /etc/ssh/sshd_config
  3. sudo systemctl restart sshd

完了すると、次の内容が表示されます(たとえば、sftpサーバー行はコメントアウトされ、その場所にInternal-sftpが追加された新しい行を追加する必要があります)。

sudo grep Subsystem /etc/ssh/sshd_config
#Subsystem  sftp    /usr/lib/openssh/sftp-server
Subsystem   sftp    internal-sftp

セキュリティを強化する必要がある場合は、グループとchrootを使用して示されているようにこれを制限することもできます。ここそしてここ

注:scpデフォルトでは、シンボリックリンクの内容は代わりにコピーされます。〜のようにシンボリックリンク。 Rsyncを使用する-lと、シンボリックリンクにコピーするか、シンボリックリンクが参照するアイテムのコピー-Lを使用してこの動作を制御できます。特に指定しない限り、(アーカイブ)オプション-aのデフォルト値はです。シンボリックリンクをリンクにコピーします(たとえば、次の項目を指します)。-l-Lsftpいいえ(コピー済み)、この記事を書くときには、この動作を制御するオプションはありません。-rオプションのドキュメントとそのオプションの下のドキュメントをそれぞれ表示して、それを確認できます。man scpman sftp

~/.ssh/config以下は、すべてのSSHを実行して設定とIDを取得するほぼ同じコマンドの例です。

ディレクトリをリモートからローカルに繰り返しコピーします。

scp -O -rp -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"
 
rsync -saLPz --port <port> -e ssh "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"

ローカルからリモートにディレクトリを繰り返しコピーします。

scp -O -rp -P <port> "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"
 
rsync -saLPz --port <port> -e ssh "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"

SFTP構文の変更

編集:2022年9月13日:今日再テスト中に私が実行したコマンドにsftpエラーがあることが確認され、上記のコマンドを除いていくつかの免責事項が追加されました。私は個人的にシンボリックリンクに関してコピーを処理する方法について上記の違いのため、代替としてsftp推奨しません。scp

特に、スクリプトで代替品として使用することに興味があります。インタラクティブモードのみが必要な場合、またはその「バッチ」ガイドラインファイルを作成することを気にしない場合、または使用するすべてのコンピュータにすでにそのモードがインストールされているsftp場合は、ここに進む必要はありません。rsync私の次のメモは、部分的に次の内容に基づいています。この回答、いくつかの追加テストを行った。

ここで最大の苦情sftpは(他のアップロードとダウンロードの構文を使用することに加えて)文書化が非常に悪い。ビューman sftp、文法は記録されません別の言葉(これはツールですできる非対話型で使用される場合、バッチモードと対話型モードでの使用は文書化されており、そのユースケースから除外されます(サポート中は文書化されていません)。マニュアルページは一般的な使い方の例を提供しておらず、多くのGNUツールのようなより詳細な文書を提供するウェブサイトも提供しません。そして、sftp -hマニュアルページより少ない数を提供します。文字通りこのような検索エンジンやサイトがなかったら、まったくsftpオプションを放棄したはずです。

1. ローカルプール(例:ローカル端末からリモートからローカルにファイルをダウンロード)

scpこれは、上記の違い(シンボリックリンクなど)とはわずかに異なる構文を除いて、ほとんど単純であり、やや同様に機能します。これらのバリエーションの1つはインタラクティブなプロンプトにつながります。

# Download a single file with same name to current dir
sftp -pC -P <port> "<user>@<host_ip>:<SRC_PATH>"
# or
sftp -pC -P <port> "<user>@<host_ip>:<SRC_PATH>" .
 
# Download a single file to name and path in "<DST_PATH>"
sftp -pC -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"
 
# Download a folder and all of its contents,
# keep the same name as the remote and save to current dir
# note that any symlinks will copy only the symlink itself
# and NOT the data the link references
sftp -rpC -P <port> "<user>@<host_ip>:<SRC_PATH>" .
 
# Now if you omit "<DST_PATH>" entirely like you can with
# the single-file version (first command in this code-block)
# you instead drop to an interactive prompt and have to type
# type 'exit' to get back to your bash prompt
# e.g. AVOID THIS IN NON-INTERACTIVE SCRIPTS!!!
sftp -rpC -P <port> "<user>@<host_ip>:<SRC_PATH>"
Connected to <host_ip>.
Changing to: <SRC_PATH>
sftp> 
sftp> exit
  
# Download a folder and all of its contents,
# to name and path in "<DST_PATH>"
# note that any symlinks will copy only the symlink itself
# and NOT the data the link references
sftp -rpC -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"

2.ローカルプッシュ(たとえば、ローカル端末からローカルからリモートへのファイルのアップロード)

まず、元の答えのようにパラメータを逆にしようとすると、接続エラーが発生します。sftpアップロード構文がダウンロード構文と一致しないのはなぜですか?あなたの推測は私と同じくらい素晴らしいです。私自身もこの方法の熱烈なファンです。ただし、試してみると、次のことが起こります(注:この出力は、sshが正しく設定されたFedora 35を実行している2つのシステムからのものであり、scp認証rsync ... -e sshメッセージなしでうまく機能します)。

# single file
sftp -pC -P <port> test.txt "<user>@<host_ip>:<DST_PATH>"
ssh: Could not resolve hostname test.txt: Name or service not known
Connection closed.  
Connection closed

# dir
sftp -rpC -P <port> "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"
ssh: Could not resolve <SRC_PATH>: Name or service not known
Connection closed.  
Connection closed

すべて回答上記でリンクしましたが、正しい方法は次のとおりです。

# push a single file from local to remote
sftp -pC -P <port> "<user>@<host_ip>:<DST_PATH>" <<< 'put test.txt'
# or
echo 'put test.txt' | sftp -pC -P <port> "<user>@<host_ip>:<DST_PATH>"

# push a entire dir (and its contents) from local to remote
# notice the inner single quotes to escape <SRC_PATH>
# for enclosing paths containing whitespace
sftp -rpC -P <port> "<user>@<host_ip>:<DST_PATH>" <<< "put '<SRC_PATH>'"
# or
echo "put '<SRC_PATH>'" | sftp -rpC -P <port> "<user>@<host_ip>:<DST_PATH>"
# or
printf 'put "%s" "%s"\n' "<SRC_PATH>" "<DST_PATH>" | \
sftp -rpC -P <port> "<user>@<host_ip>"

たとえば、ダウンロードに似た構文を使用するスクリプトを見つけました。

# pull a entire dir (and its contents) from remote to local
# notice the inner single quotes to escape <SRC_PATH>
# for enclosing paths containing whitespace
printf 'get "%s" "%s"\n' "<SRC_PATH>" "<DST_PATH>" | \
sftp -rpC -P <port> "<user>@<host_ip>"

あまり混乱しませんが、上記のすべてがうまくいくはずです。

put複数のパスを一度にコピーするには、配列を使用できます(または各コマンドを別々の行にリストするバッチファイルを作成し、sftpuse-b <batchfile>オプションを渡すことができます)。

# copy multiple paths from array
arrPaths=("<SRC_PATH_1>" "<SRC_PATH_2>" "<SRC_PATH_3>");
printf 'put %s\n' "${arrPaths[@]}" | sftp -rpC -P <port> "<user>@<host_ip>:<DST_PATH>"

2022年10月10日に更新されました。スペースを含むコピーにいくつかの問題が発生した後、オプションを使用するようにrsyncコマンドを更新しました(-sこの回答)

しかし、私はrsyncがスペース処理scpとは異なりsftp(スペース処理の観点から)、scp内部引用符を含むパスには常にOKです。

scp -rp "remoteuser@remotehost:'/tmp/rsync-test/stuff from server/the data.txt'" "."

ただし、この操作を実行するとrsyncエラーが発生します。

$ rsync -saXULz --progress -e ssh \
  "remoteuser@remotehost:'/tmp/rsync-test/stuff from server/the data.txt'" "."
 
receiving incremental file list
rsync: [sender] change_dir "/home/remoteuser/'/tmp/rsync-test/stuff from server" failed: No such file or directory (2)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1839) [Receiver=3.2.5]
rsync: [Receiver] write error: Broken pipe (32)

この問題を解決するのは非常に簡単ですが、私のscpように内部引用符の構文を使用することに慣れている場合は直感的ではないかもしれません。-s内部引用符を使用して削除するだけです。rsyncそれを処理できるほどスマートであれば、実際に動作します。

したがって、上記の誤ったコマンドを次のように変更するだけです。

$ rsync -saXULz --progress -e ssh \
  "remoteuser@remotehost:/tmp/rsync-test/stuff from server/the data.txt" "."

すべてがうまくいくはずです(scpすべてが同じパスでうまくいくと仮定します)。

関連情報