SSH: предоставьте дополнительные «pipe» fd в дополнение к stdin, stdout, stderr

12

При подключении к хосту с SSH, как правило , три «труба» предусмотрена между хостом и гостем, для stdin, stdoutи stderr.

Есть ли опция командной строки для создания пересылок для дополнительных файловых дескрипторов ( 3и далее)?

Например, я хотел бы сделать

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

который напечатал бы 'test' в локально открытый дескриптор файла 10.

мышей
источник
2
Вероятно, не без сложного редактирования исходного кода, учитывая различные closefrom(STDERR_FILENO + 1)вызовы из исходного кода OpenSSH. Что вы пытаетесь сделать, что требует этого?
thrig
Протокол поддерживает туннелирование дополнительных потоков, кроме stdin/ out/ err, но, AFAIK, ни один сервер / клиент никоим образом не поддерживает эту функцию.
Сальва
@thrig Не OP, и это было давно, но на тот случай, если вам все еще интересно, для чего это может быть полезно, я надеялся найти здесь подсказку о том, как передать по ssh, скрипт для bash и Стандартный для этого сценария. Что-то похожее на: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 
Jakuje
источник
1

Я уверен, что это должно быть возможно. Я могу только предложить взломать, когда вы используете дополнительные ssh-соединения, чтобы каждый переносил другую пару файловых дескрипторов. Например, следующий сценарий проверки концепции делает первый ssh ​​для запуска фиктивной команды (sleep) для подключения локальных fds 5 и 6 к удаленным stdin и stdout, предполагая, что эти fds вы хотите добавить к обычному 0,1, 2.

Затем выполняется настоящий ssh, и на удаленном компьютере он соединяет удаленные fds 5 и 6 со стандартным и стандартным sdin другого ssh.

Как пример, этот скрипт передает man-страницу в формате gzipped на удаленный компьютер, который распаковывает и запускает ее через man. Stdin и stdout реального ssh по-прежнему доступны для других целей.

#!/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
источник
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это НЕ достаточно!) , Чтобы использовать перенаправление локального сокета для передачи файлов:

# 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 -tдля выделения TTY.

Проблема с этим решением состоит в том, что вы должны жестко закодировать пути локальных сокетов UNIX: локально это не такая большая проблема, как вы можете включить $$в путь, чтобы сделать его уникальным для процесса или пользователя во временном каталоге, но в удаленный конец, вам лучше не использовать каталог для записи в мире, /tmp/как я делаю в моем примере. Каталог также должен существовать при sshзапуске сеанса. И inode сокета останется даже после закрытия сеанса, поэтому использование что-то вроде "$ HOME / .ssh. $$" будет загромождать ваш каталог мертвыми inode с течением времени.

Вы также можете использовать привязанные к TCP-сокеты localhost, что избавит вас от загромождения файловых систем мертвыми inode, но даже с ними вам все равно придется выбирать (уникальный) неиспользуемый номер порта. Так что до сих пор не идеал. ( sshимеет код для динамического распределения портов, но я не нашел способа получить эту информацию на удаленном хосте.)

Вероятно, самое простое решение для копирования файлов - использовать встроенную функцию обмена соединениями в ssh и выполнить команду scpили, sfrpпока интерактивный сеанс все еще работает параллельно. См. Скопируйте файл обратно в локальную систему с помощью ssh .

pmhahn
источник