デバイスから数分ごとに自動リモートSSHポート転送要求を行っています。
ssh -y -f -N -R port:localhost:22 user@server \
-o ExitOnForwardFailure=yes -o ServerAliveInterval=60 \
-o StrictHostKeyChecking=no
ポート転送が成功し、デバイスを再起動してインターネット接続をリセットすると、デバイスに接続したり、新しいポート転送を行ったりすることができません(これは正常であり、IPが変更され、ポートが占有されているようです)。ポートが再び解放されるまで約1〜2時間待つ必要があります。そうしないと、サーバー上のプロセスを強制終了する必要があります。
デバイスをオフにする前に、ポートを解放するスクリプトをデバイスから送信して、再起動後に新しいポート転送要求が成功するようにしたいと思います。
要約すると、サーバー上のプロセスを強制終了するのではなく、要求したデバイスからのポート転送をリモートでキャンセルするにはどうすればよいですか?
サーバーで次のsshd
オプションを使用します(_sshd_config
_ファイル内):
_ClientAliveCountMax 3
ClientAliveInterval 15
_
サーバー上のプロセスを強制終了する代わりに、要求したデバイスからのポート転送をリモートでキャンセルするにはどうすればよいですか?
簡単な答えは、クライアントでssh
を終了するだけです。強制的に強制終了した場合でも、接続が終了したことをサーバーに通知する必要があります( ジョブを実行するのはカーネルであるため )。
…通知がサーバーに届いた場合、つまり。これが問題だと思います。 ssh
が終了する前に、デバイスのネットワークが何らかの理由で切断され、この特定のSSH接続が終了したことをサーバーに通知する方法がありません。
たぶん、クライアント側のセットアップを再設計して、ネットワーク接続に対して何かが行われる前にssh
が確実に終了するようにすることができます。クライアント側のシステムの詳細がわからないので、何がどのようにできるのか正確には説明しません。緩い例:systemd
ユニットとその依存関係(該当する場合)。 reboot
および/またはshutdown
のラッパー。
SSHサーバーは標準のsshd
だと思います。そのデフォルト設定(_sshd_config
_)は
_TCPKeepAlive yes
_
から _man 5 sshd_config
_ :
TCPKeepAlive
システムがTCPキープアライブメッセージを反対側に送信するかどうかを指定します。送信された場合、接続の停止またはいずれかのマシンのクラッシュが適切に通知されます。ただし、これは接続が意味します。ルートが一時的にダウンしていると死に、一部の人はそれを煩わしく感じます。一方、TCPキープアライブが送信されない場合、セッションはサーバー上で無期限にハングし、「ゴースト」が残る可能性があります。 'ユーザーとサーバーリソースの消費。
デフォルトは
yes
(TCPキープアライブメッセージを送信するため))であり、サーバーはネットワークがダウンしたかクライアントホストがクラッシュしたかを認識します。これにより、セッションが無限にハングするのを防ぎます。
このメカニズムはSSHに固有のものではありません。説明:
Linuxでは、TCPキープアライブパラメーターは次のとおりです。
_
tcp_keepalive_intvl
_
_tcp_keepalive_probes
_
_tcp_keepalive_time
_デフォルト値は次のとおりです。
_
tcp_keepalive_time = 7200
_(秒)
_tcp_keepalive_intvl = 75
_(秒)
_tcp_keepalive_probes = 9
_(プローブの数)これは、キープアライブプロセスがソケットアクティビティを2時間(7200秒)待ってから最初のキープアライブプローブを送信し、75秒ごとに再送信することを意味します。
ACK
応答が9回連続して受信されない場合、接続は切断済みとしてマークされます。
( ソース )。
これは、「ポートが再び空になるまで約1〜2時間待たなければならない」理由を説明しています。
これらの値を変更する方法の例(権限がある場合):
一時的に
_echo 300 > /proc/sys/net/ipv4/tcp_keepalive_time
_
または
_sysctl -w net.ipv4.tcp_keepalive_time=300
_
_/etc/sysctl.conf
_ファイルを編集して永続的に、以下を追加します。
_net.ipv4.tcp_keepalive_time=300
_
次に、_Sudo sysctl -p
_を呼び出して変更を適用します。
しかしこれらはシステム全体の設定です。一般に、変更はsshd
以上に影響します。そのため、SSH固有のソリューションを使用することをお勧めします。再び _man 5 sshd_config
_ から:
ClientAliveCountMax
sshd(8)
がクライアントからメッセージを受信せずに送信できるクライアントアライブメッセージ(以下を参照)の数を設定します。クライアントアライブメッセージの送信中にこのしきい値に達すると、sshd
はクライアントを切断し、セッションを終了します。クライアントアライブメッセージの使用はTCPKeepAlive
とは大きく異なることに注意することが重要です。 […]クライアントアライブメカニズムは、クライアントまたはサーバーが接続が非アクティブになったことを知ることに依存している場合に役立ちます。デフォルト値は_
3
_です。ClientAliveInterval
(以下を参照)が_15
_に設定され、ClientAliveCountMax
がデフォルトのままの場合、応答しないSSHクライアントは約45秒後に切断されます。このオプションは、プロトコルバージョン2にのみ適用されます。
ClientAliveInterval
タイムアウト間隔を秒単位で設定します。その後、クライアントからデータを受信しなかった場合、
sshd(8)
は暗号化されたチャネルを介してメッセージを送信し、クライアントからの応答を要求します。デフォルトは_0
_で、これらのメッセージがクライアントに送信されないことを示します。このオプションは、プロトコルバージョン2にのみ適用されます。
サーバー上でsshd
を再構成できるのであれば、これが最もエレガントな方法だと思います。_sshd_config
_次のような行が含まれています:
_ClientAliveCountMax 3
ClientAliveInterval 15
_
ノート:
-o ServerAliveInterval=60
_は、ssh
の同様のオプションです。これにより、クライアントは接続の切断を検出できます。ただし、サーバーには影響しません。autossh
を検討することができます。サーバーもクライアントも再構成できないとしましょう。私はあなたが言ったことを知っています
サーバー上のプロセスを強制終了する代わりに
しかし、この場合、それを殺すことは最良の選択肢かもしれません。 sshd
フォークは特定の接続を提供するため、残りのプロセスに影響を与えることなく、適切なプロセスを強制終了するだけで十分です。クライアントからの強制終了を開始するには、ssh
を呼び出す方法を変更する必要があります。あなたが言った:
数分ごと:
_ssh -f …
_
これの代わりに、次のようなスクリプトを1回だけ実行できます(たとえば、crontabの_@reboot
_経由)。最初に(サーバー上のsshd
の)保存されたPIDを強制終了しようとし、次にトンネルを確立してそのsshd
PIDを保存します。トンネルを確立できないか、最終的に終了した場合、スクリプトはしばらくスリープしてループします。
_#!/bin/sh
port=12345
address=user@server
while :; do
ssh $address '[ -f ~/.tunnel.pid ] && kill `cat ~/.tunnel.pid` && rm ~/.tunnel.pid'
ssh -o ExitOnForwardFailure=yes -R ${port}:localhost:22 $address 'echo $PPID > ~/.tunnel.pid; exec sleep infinity'
sleep 60
done
_
ノート:
転送は、ssh
エスケープ文字(デフォルトでは行頭の~
)または~?
を使用してキャンセルできます。
Supported escape sequences:
~. - terminate connection (and any multiplexed sessions)
~B - send a BREAK to the remote system
~C - open a command line
~R - request rekey
~V/v - decrease/increase verbosity (LogLevel)
~^Z - suspend ssh
~# - list forwarded connections
~& - background ssh (when waiting for connections to terminate)
~? - this message
~~ - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)
~#
は接続を一覧表示しますが、コマンドを介して接続を強制終了するのに適した方法ではありません
The following connections are open:
#3 client-session (t4 r0 i0/0 o0/0 fd 8/9 cc -1)
これは~C
、次にhelp
で見つけることができます
ssh> help
Commands:
-L[bind_address:]port:Host:hostport Request local forward
-R[bind_address:]port:Host:hostport Request remote forward
-D[bind_address:]port Request dynamic forward
-KL[bind_address:]port Cancel local forward
-KR[bind_address:]port Cancel remote forward
-KD[bind_address:]port Cancel dynamic forward
したがって、理論的には、~C-KL22
を介してコマンドラインを開き、ポート番号でLocalForward
をキャンセルすることができます。
これで問題が解決するかどうかは不明です。ポートは通常、TIME_WAIT
などをクリアするのに1〜2時間もかかりません...