SSH: Надайте додаткові FD “pipe”, крім stdin, stdout, stderr


12

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

Чи є варіант командного рядка для створення форвардів для додаткових дескрипторів файлів ( 3і далі)?

Наприклад, я хотів би це зробити

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

який виводив би "тест" на дескриптор 10 відкритого локально файлу.


2
Можливо, не обійшлося без складних редагувань джерела, враховуючи різні closefrom(STDERR_FILENO + 1)дзвінки під вихідним кодом OpenSSH. Що ви намагаєтесь зробити, що цього вимагає?
трич

Протокол підтримує тунелювання додаткових потоків, окрім 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 ​​для запуску манекенної команди (сну) для підключення локальних Fds 5 та 6 до віддалених stdin та stdout, припускаючи, що ці FDS є тими, які ви хочете додати до звичайних 0,1, 2.

Потім виконується справжній ssh, а на віддаленому він підключає віддалені fds 5 та 6 до stdin та stdout іншого ssh.

Так само, як приклад, цей скрипт передає gzipped man сторінку до пульта, який розпаковує та запускає його через 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

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. $$" буде збивати ваш каталог з мертвими вводами протягом певного часу.

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

Мабуть, найпростішим рішенням для копіювання файлів є використання вбудованої функції спільного доступу до ssh та виконання команд scpабо sfrpкоманд, поки ваш інтерактивний сеанс все ще працює паралельно. Див. Розділ Копіювання файлу до локальної системи за допомогою ssh .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.