Openssh 클라이언트는 stderr이 stdout으로 리디렉션되면 영원히 차단됩니다.

Openssh 클라이언트는 stderr이 stdout으로 리디렉션되면 영원히 차단됩니다.

뭔가 문제가 있는 것 같습니다 openssh. bash셸 에서 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
...

답변2

왜 이런 일이 발생합니까?

쉘이 도착하기 전에 cat종료가 필요합니다 echo. 존재하기 때문에 "영구적으로 차단"됩니다 cat.

해결책이 있나요?

Bash에서는 차단 없이 실행하기 위해 프로세스 대체를 사용합니다 cat. cat방해가 되지 않으면 정말 echo OK괜찮은 경우 에만 ( &&또는 을 사용하여) $?쉽습니다 . 예:

ssh -f … > >(cat -A) 2>&1 && echo OK; echo "The script goes on."

이제 백그라운드로 이동하기 cat전후에 작동 ssh하지만 스크립트는 ssh실행되자마자 계속됩니다(또는 ssh백그라운드로 이동하지 않고 실패합니다).

관련 정보