SSH : stdin, stdout, stderr 외에 추가 "파이프"fd를 제공합니다


12

SSH를 사용하여 호스트에 연결하는 경우 일반적으로 호스트와 게스트 사이 stdinstdout,, 및 세 개의 "파이프"가 제공됩니다 stderr.

추가 파일 디스크립터 ( 3및 이후)에 대한 전달을 작성하는 명령 행 옵션이 있습니까?

예를 들어,하고 싶습니다

ssh --forwardfd=10:3 remotehost 'echo test >&3'

로컬로 열린 파일 디스크립터 10에 'test'를 인쇄합니다.


2
closefrom(STDERR_FILENO + 1)OpenSSH 소스 코드 아래의 다양한 호출을 고려할 때 까다로운 소스 편집이 없을 수 있습니다. 이것을 요구하는 것은 무엇입니까?
thrig

이 프로토콜은 stdin/ out/ 이외의 추가 스트림 터널링을 지원 err하지만 AFAIK는 서버 / 클라이언트가 해당 기능을 지원하지 않습니다.
살바

@thrig OP가 아니며 오랜 시간이 지났지 만 이것이 여전히 유용한 점이 궁금한 경우 ssh를 통해 파이프하는 방법에 대한 단서, bash 및 해당 스크립트에 대한 stdin. 비슷한 내용 :infinite-output-cmd | ssh user@host bash /proc/self/fd/3 3< local-script-to-execute-remotely.sh
JoL

@thrig 그것은 나 --forwardfd에게도 필요하지 않은 것이 발생 합니다. ssh다른 것을 열기 전에 열린 파일 디스크립터가 무엇인지 확인하고 원격의 동일한 파일 디스크립터에 자동으로 전달할 수 있습니다. 내 예처럼 완전히 투명 할 수 있습니다. 나는 그것을 위해 패치하는 것이 얼마나 어려운지 궁금합니다 ssh. 당신이 말했듯이, 그 이유 뒤에 따라 까다로울 수 있습니다 closefrom(STDERR_FILENO + 1).
JoL

답변:


6

openssh-6.7부터 사용할 수있는 소켓 전달을 사용하여이 작업을 수행 할 수 있습니다. 이것은 일종의 파이프입니다. 이 기술은 예를 들어 여기에 설명되어 있습니다 : http://www.25thandclement.com/~william/projects/streamlocal.html

데이터에 대한 양방향 경로를 얻게됩니다. mysql의 예가 있습니다.

원격 서버에서 로컬 인스턴스로 프록시 MySQL 클라이언트 연결 :

ssh -R/var/run/mysql.sock:/var/run/mysql.sock \
    -R127.0.0.1:3306:/var/run/mysql.sock somehost 

1

나는 그것이 가능할 것이라고 확신한다. 여분의 ssh 연결을 사용하여 다른 파일 설명자 쌍을 가지고있는 해킹 만 제안 할 수 있습니다. 예를 들어, 다음 개념 증명 스크립트는 첫 번째 ssh에서 더미 명령 (sleep)을 실행하여 로컬 fd 5 및 6을 원격 stdin 및 stdout에 연결합니다. 이러한 fd는 일반적인 0,1에 추가하려는 것으로 가정합니다. 2.

그런 다음 실제 ssh가 완료되고 원격에서 원격 fd 5 및 6을 다른 ssh의 stdin 및 stdout에 연결합니다.

예를 들어,이 스크립트는 gzip으로 압축 된 매뉴얼 페이지를 원격으로 전달합니다.이 페이지는 압축을 풀고 man을 통해 실행합니다. 실제 ssh의 stdin 및 stdout은 여전히 ​​다른 용도로 사용할 수 있습니다.

#!/bin/bash
exec 5</usr/share/man/man1/ssh.1.gz 6>/tmp/out6 # pretend need 5 and 6

ssh remote 'echo $$ >/tmp/pid; exec sleep 99999' <&5 >&6 &
sleep 1 # hack. need /tmp/pid to be set

ssh remote '
  pid=$(</tmp/pid) 
  exec 5</proc/$pid/fd/0 6>/proc/$pid/fd/1
  echo start
  gzip -d <&5 | man /dev/stdin >&6
  echo stop
  kill -hup $pid
'
wait
less /tmp/out6

1

@jakuje의 대답에 대한 문제는 소켓 에서만 작동 하지만 파일 을 기대하는 사용자 표준 UNIX 도구는 사용할 수 없다는 것입니다.

ssh -R/tmp/sock.remote:/tmp/sock.local "$HOST" 'LANG=C cat >/tmp/sock.remote'

bash : /tmp/sock.remote : 해당 장치 나 주소가 없습니다.

또한 로컬 소켓 파일이 원격 호스트에서 삭제되지 않는 문제가 있습니다. 다음에 동일한 명령을 실행하면 경고가 표시되고 소켓이 올바르게 다시 작성되지 않습니다. 오래된 소켓을 연결 해제하는 옵션 -o StreamLocalBindUnlink=yes을 제공 할 수 ssh있지만 테스트에서는 충분하지 않습니다. 또한 해당 옵션이 작동 하도록 편집해야 sshd_config합니다 StreamLocalBindUnlink=yes.

하지만 당신은 사용할 수 있습니다 socat또는 netcat또는 지원하는 다른 유사한 도구 UNIX 지역 소켓 ( netcat-traditional이다 NOT 충분히!) 파일 전송을위한 로컬 소켓 전달을 사용 :

# start local process listening on local socket, which receives the data when ssh opens the connections and saves it to a local file
nc -l -N -U /tmp/sock.local >/tmp/file.local &
# connect to remote $HOST and pipe the remote file into the remote socket end
ssh \
 -o ExitOnForwardFailure=yes \
 -o StreamLocalBindUnlink=yes \
 -R /tmp/sock.remote:/tmp/sock.local \
 "$HOST" \
 'nc -N -U /tmp/sock.remote </tmp/file.remote'

대화식 명령을 실행할 수도 있습니다.이 경우 ssh -tTTY를 할당하는 데 사용해야합니다.

이 솔루션의 문제점은 UNIX 로컬 소켓의 경로를 하드 코딩해야한다는 것입니다. 로컬 적으로 이것은 $$프로세스 나 사용자별로 고유 한 디렉토리로 경로에 포함시킬 수있는만큼 큰 문제는 아니지만 remote-end /tmp/내 예제에서와 같이 world-writeable 디렉토리 를 사용하지 않는 것이 좋습니다 . ssh세션이 시작될 때 디렉토리도 이미 존재해야합니다 . 소켓 inode는 세션이 닫힌 후에도 유지되므로 "$ HOME / .ssh. $$"와 같은 것을 사용하면 시간이 지남에 따라 죽은 inode로 디렉토리가 복잡해집니다.

또한 TCP 소켓을 바인딩하여 사용할 수 있습니다. 그러면 localhost죽은 inode로 파일 시스템을 어지럽히 지 않아도되지만 여전히 사용하지 않는 (고유 한) 포트 번호를 선택하는 데 문제가 있습니다. 여전히 이상적이지 않습니다. ( ssh동적으로 포트를 할당하는 코드가 있지만 원격 호스트에서 해당 정보를 검색 할 방법이 없습니다.)

아마도 파일을 복사하는 가장 쉬운 해결책은 ssh의 내장 연결 공유 기능을 사용하고 대화식 세션이 여전히 병렬로 실행되는 동안 scp또는 sfrp명령 을 수행하는 것 입니다. ssh를 사용하여 파일을 로컬 시스템으로 다시 복사를 참조하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.