Openssh クライアントは、stderr が stdout にリダイレクトされると永久にブロックされます。

Openssh クライアントは、stderr が stdout にリダイレクトされると永久にブロックされます。

何か問題があるようですopensshbashシェルからstderrリダイレクトするとstdout永久にブロックされるため、次のことを行う必要がありますKeyboardInterrupt

$ ssh -fTNF './config' -MS './sockd5/ctrl_socket' -i './keys/id_rsa' -l 'root' -p '22' 'example.com' 2>&1 | cat -A; echo OK
ControlSocket ./sockd5/ctrl_socket already exists, disabling multiplexing^M$
^C

リダイレクトせずに同じコマンドが正常に動作します。

$ ssh -fTNF './config' -MS './sockd/ctrl_socket' -i './keys/id_rsa' -l 'root' -p '22' 'example.com' | cat -A; echo OK
ControlSocket ./sockd/ctrl_socket already exists, disabling multiplexing
OK

なぜこれが起こるのですか?解決策はありますか?

ベストアンサー1

ssh -fホストに接続して認証した後、「バックグラウンドに移動」すると、stdin、stdout、および stderr の元の開いたハンドルが維持され、そのハンドルが別のプロセス (たとえば stdout + stderr cat -A) にパイプされている場合、必要なくなった場合でもプロセスをアクティブに保つ効果があります。

ssh呼び出してプロセス自体をデーモン化します。daemon(3)ライブラリ関数ですが、それを呼び出すために使用されるため、noclose = 1stdin / stderr / stdoutをリダイレクトできません/dev/null

この問題は、最新バージョンで部分的に修正されましたopenssh(メイン制御プロセス - stdinとstdoutの場合)。2010年、標準エラー2016年;セッションプロセスの場合 - 標準出力2017年)しかし、古いsshを実行する必要がある場合、またはstderrへのこだわりを停止する必要がある場合は、唯一の「解決策」はhackを使用し、を使用するラッパーで関数をオーバーライドするLD_PRELOADことです。daemon(3)noclose = 0

$ cat daemon-force-close.c
#define _GNU_SOURCE
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>

int daemon(int nochdir, int noclose){
        static int (*orig)(int, int);
        if(!orig && !(*(void**)&orig = dlsym(RTLD_NEXT, "daemon")))
                errx(1, "%s", dlerror());
        return orig(nochdir, 0);
}

$ cc -shared -Wall -O2 daemon-force-close.c -ldl -o daemon-force-close.so

$ LD_PRELOAD=./daemon-force-close.so \
   ssh -Nf dummy@localhost -MS ./ctlsock 2>&1 | cat -A
dummy@localhost's password:
$
[no Ctrl-C needed]
$ ssh -S ~/w/c/ctlsock dummy@localhost
Last login: Tue May 28 21:04:26 2019 from ::1
...

おすすめ記事