Сценарій Bash для налаштування тимчасового тунелю SSH


132

У Cygwin я хочу, щоб сценарій Bash:

  1. Створіть тунель SSH для віддаленого сервера.
  2. Виконайте якусь роботу на місцях, яка використовує тунель.
  3. Потім закрити тунель.

Частина відключення мене здивувала.

Наразі у мене є кульгаве рішення. В одній оболонці я запускаю наступне, щоб створити тунель:

# Create the tunnel - this works! It runs forever, until the shell is quit.
ssh -nNT -L 50000:localhost:3306 jm@sampledomain.com

Потім в іншому вікні оболонки я виконую свою роботу:

# Do some MySQL stuff over local port 50000 (which goes to remote port 3306)

Нарешті, коли я закінчую, я закриваю перше вікно оболонки, щоб вбити тунель.

Я хотів би зробити це все в одному сценарії, як:

# Create tunnel
# Do work
# Kill tunnel

Як слідкувати за процесом тунелю, щоб я знав, кого вбити?


Я написав сценарій, який допоможе зробити тунелінг
Nam Nguyen

Відповіді:


324

Це можна зробити чисто за допомогою ssh 'control socket'. Щоб поговорити з уже запущеним процесом SSH і отримати його pid, вбийте його тощо. Використовуйте "керуючий сокет" (-M для master і -S для socket) наступним чином:

$ ssh -M -S my-ctrl-socket -fnNT -L 50000:localhost:3306 jm@sampledomain.com
$ ssh -S my-ctrl-socket -O check jm@sampledomain.com
Master running (pid=3517) 
$ ssh -S my-ctrl-socket -O exit jm@sampledomain.com
Exit request sent. 

Зауважте, що my-ctrl-socket буде фактичним створеним файлом.

Я отримав цю інформацію з дуже відповіді RTFM у списку розсилки OpenSSH .


6
Це найкраща відповідь, яку я бачив до цього часу. Дуже дякую, це має бути прийнятим. Я використовую це для підключення до моєї програми Vagrant VM та запуску сценарію оновлення FlywayDB.
Крістіан

2
Мабуть, керуючі розетки працюють не скрізь. Наприклад, я потрапляю Operation not permittedна безперервне інтеграційне середовище muxserver_listen: link mux listener ssh-ctrl-socket.wsASkszgSBlK7kqD => ssh-ctrl-socket: Operation not permitted
drone.io

Отже, що відбувається з my-ctrl-socketфайлом після запуску? Коли я ls -laперебуваю в поточній папці, я більше не бачу файл.
sachinruk

2
Якщо ви використовуєте його в сценарії, вам потрібно дочекатися появи розетки управління кілька секунд. Моє рішення:while [ ! -e $ctrl_socket ]; do sleep 0.1; done
Адам Уолнер

коли я це роблю, я отримую, open failed: administratively prohibited: open failedі не думаю, що це відкриває тунель
Енді Рей

21

Ви можете сказати SSH самому тлутись за допомогою параметра -f, але PID з $! Крім того, замість того, щоб ваш сценарій спав довільну кількість часу перед тим, як використовувати тунель, ви можете використовувати -o ExitOnForwardFailure = так з -f і SSH буде чекати, коли всі віддалені порти вперед будуть успішно встановлені, перш ніж розмістити себе у фоновому режимі. Ви можете присвоїти вихід PS, щоб отримати PID. Наприклад, ви можете використовувати

...
ssh -Cfo ExitOnForwardFailure=yes -NL 9999:localhost:5900 $REMOTE_HOST
PID=$(pgrep -f 'NL 9999:')
[ "$PID" ] || exit 1
...

і будьте впевнені, що ви отримаєте потрібний PID


Ви можете цього не усвідомлювати, але це свого роду геній. Я шукав спосіб відстежити PID тунелів SSH і майже в кінцевому підсумку використовував сценарії службових систем. Більше не можна: я можу схрестити процес SSH, який мені потрібен, використовуючи назву тунелю. Ця ідея якось повністю пропустила мене. Дуже дякую!
aexl

19
  • Ви можете сказати sshпереходити на задній план із, &а не створювати оболонку з іншого боку (просто відкрийте тунель) із прапором командного рядка (я бачу, ви це вже робили -N).
  • Збережіть PID за допомогою PID=$!
  • Робіть свої речі
  • kill $PID

EDIT: Фіксований $? до $! і додав &


3
Якщо мій сценарій вмирає десь до того, як він потрапить у Вбивство, я повинен бути обережним, щоб впоратися з цим.
джм.

2
@jm: trap 'kill $PID' 1 2 15охопить багато випадків відмови сценарію.
Норман Ремзі

3
Щоб це надійно працювало, мені довелося трохи «поспати» ПІСЛЯ створення тунелю, але перед тим, як використовувати його.
джм.

@NormanRamsey Я думаю, ви маєте на увазі trap "kill $PID", тому що bash буде інтерполювати змінні всередині подвійних цитованих рядків
JuanCaicedo

1
@JuanCaicedo Відмінність буде важливою лише в тому випадку, якщо PIDзмінна буде переглянута пізніше. Змінна або розширюється, коли викликається trapвбудований (підхід ОП), або коли сигнал потрапив (ваш підхід); обидва підходи тут дають однаковий результат.
Вітіко

4

Я вважаю за краще запустити нову оболонку для окремих завдань і часто використовую таку комбінацію команд:

  $ sudo bash; exit

або іноді:

  $ : > sensitive-temporary-data.txt; bash; rm -f sensitive-temporary-data.txt; exit

Ці команди створюють вкладену оболонку, де я можу виконати всю свою роботу; коли я закінчую, я натискаю CTRL-D, і батьківська оболонка очищається і виходить також. Ви можете легко кинути bash;в скрипт тунелю ssh безпосередньо перед killчастиною, так що коли ви вийдете з вкладеної оболонки, ваш тунель буде закритий:

#!/bin/bash
ssh -nNT ... &
PID=$!
bash
kill $PID

Дуже цікаво. Це може краще вирішити проблему "пастки". Доведеться спробувати.
джм.

2

Ви можете запустити конец sshз &кінцем, поставити його на другий план і схопити його ідентифікатор під час виконання. Тоді ви просто повинні зробити killцей ідентифікатор, коли закінчите.


Будьте в курсі, якщо ви використовуєте ampersand ("&"). Це некрасивий підхід, оскільки вам доведеться визначити фактичний зв’язок, встановлений для себе. Це може призвести до подальшого виконання коду, який не чекає повного встановлення фактичного з'єднання. Крім того, з'єднання не буде вбито автоматично, якщо сценарій розривається.
Джонатан

2

Ще один потенційний варіант - якщо ви можете встановити очікуваний пакет, ви повинні мати можливість все-таки сценаріювати. Деякі хороші приклади тут: http://en.wikipedia.org/wiki/Expect

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