SSH: forneça fds “pipe” adicionais, além de stdin, stdout, stderr

12

Ao se conectar a um host com SSH, geralmente três "tubos" são fornecidos entre anfitrião e convidado, para stdin, stdout, e stderr.

Existe uma opção de linha de comando para criar encaminhamentos para descritores de arquivos adicionais ( 3e posteriores)?

Por exemplo, eu gostaria de fazer

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

que imprimiria 'test' no descritor de arquivo aberto localmente 10.

ratos
fonte
2
Provavelmente não sem edições complicadas de fonte, dadas as várias closefrom(STDERR_FILENO + 1)chamadas no código-fonte OpenSSH. O que você está tentando fazer e exige isso?
thrig
O protocolo suporta o encapsulamento de fluxos adicionais além de stdin/ out/ err, mas o AFAIK, nenhum servidor / cliente oferece suporte de qualquer maneira a esse recurso.
salva 15/02
@thrig Não OP, e já faz muito tempo, mas, se você ainda está curioso para saber o que isso poderia ser útil, o que eu esperava encontrar aqui era uma pista sobre como passar pelo ssh, um script para bash e o stdin para esse script. Algo semelhante a:infinite-output-cmd | ssh user@host bash /proc/self/fd/3 3< local-script-to-execute-remotely.sh
JOL
@thrig Ocorre-me que algo assim --forwardfdnem deveria ser necessário. sshpode verificar quais são os descritores de arquivos abertos antes de abrir qualquer outra coisa e encaminhá-los automaticamente para os mesmos descritores de arquivos no lado remoto. Poderia ser totalmente transparente como no meu exemplo. Eu me pergunto o quão difícil seria consertar sshisso. Como você disse, pode ser complicado, dependendo das razões por trás disso closefrom(STDERR_FILENO + 1).
JOL

Respostas:

6

Você pode fazer isso usando o encaminhamento de soquete, disponível desde o openssh-6.7. Isso é algum tipo de cano. Esta técnica é descrita, por exemplo, aqui: http://www.25thandclement.com/~william/projects/streamlocal.html

Você obterá uma rota de duas direções para seus dados. Há um exemplo com o mysql:

Proxy de conexões do cliente MySQL em um servidor remoto com sua instância local:

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

Tenho certeza que deveria ser possível. Só posso sugerir um hack onde você usa conexões ssh extras para cada uma delas transportar outro par de descritores de arquivo. Por exemplo, o script de prova de conceito a seguir executa um primeiro ssh para executar um comando fictício (suspensão) para conectar os fds locais 5 e 6 ao stdin e stdout remotos, presumindo que esses fds sejam os que você deseja adicionar ao valor usual 0,1, 2)

Em seguida, o ssh real é concluído e, no controle remoto, ele conecta os fds 5 e 6 remotos ao stdin e stdout do outro ssh.

Apenas como exemplo, esse script passa uma página de manual compactada para o controle remoto, que descompacta e a executa no man. O stdin e stdout do ssh real ainda estão disponíveis para outras coisas.

#!/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
meuh
fonte
1

O problema com a resposta do @jakuje é: ele funciona apenas com soquetes , mas você não pode usar ferramentas UNIX padrão que esperam arquivos com eles:

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

bash: /tmp/sock.remote: Esse dispositivo ou endereço não existe

Também há o problema de o arquivo de soquete local não ser excluído no host remoto; na próxima execução do mesmo comando, você recebe um aviso e o soquete não é recriado corretamente. Você pode dar a opção -o StreamLocalBindUnlink=yesde sshdesvincular esse soquete antigo, mas nos meus testes não foi suficiente; você também tem que editar você sshd_configpara conter StreamLocalBindUnlink=yespara essa opção ao trabalho.

Mas você pode usar socatou netcatqualquer outra ferramenta similar que suporte soquetes locais UNIX ( NÃOnetcat-traditional é suficiente!) Para usar o encaminhamento de soquete local para transferência de arquivos:

# 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'

Você também pode executar comandos interativos; nesse caso, você deve usar ssh -tpara alocar TTYs.

O problema com esta solução é que você deve codificar os caminhos dos soquetes locais do UNIX: localmente, esse não é um problema que você pode incluir $$no caminho para torná-lo único por processo ou usuário em um diretório temporário, mas no diretório remoto, é melhor você não usar o diretório gravável em todo o mundo, /tmp/como eu faço no meu exemplo. O diretório também deve existir quando a sshsessão é iniciada. E o inode do soquete permanecerá mesmo após o encerramento da sessão, portanto, usar algo como "$ HOME / .ssh. $$" sobrecarregará seu diretório com inodes inoperantes ao longo do tempo.

Você também pode usar soquetes TCP vinculados localhost, o que evitará que você sobrecarregue seus sistemas de arquivos com inodes inativos, mas mesmo com eles você ainda terá problemas para escolher um número de porta (exclusivo) não utilizado. Então ainda não é o ideal. ( sshpossui código para alocar portas dinamicamente, mas não encontrei maneira de recuperar essas informações no host remoto.)

Provavelmente, a solução mais fácil para copiar arquivos é usar a funcionalidade de compartilhamento de conexão interna do ssh e executar um comando scpou sfrpenquanto sua sessão interativa ainda estiver em execução em paralelo. Consulte Copiar um arquivo de volta para o sistema local com ssh .

pmhahn
fonte