Назад | Перейти на главную страницу

Как узнать, используется ли соединение SSH ControlMaster

Я бы хотел использовать sshс ControlMaster функция обмена соединениями для увеличения скорости. Я пытаюсь написать сценарий, чтобы я мог запускать / перезапускать / останавливать несколько подключений к разным хостам.

Как я могу определить, используются ли какие-либо из этих подключений? Если я убью их, когда сеанс ssh открыт, он закроется

Мой сценарий перезапуска в идеале выглядел бы как (псевдосценарий) - сценарий остановки был бы эквивалентен без команды ssh внизу:

for HOST in $HOST_LIST
  do
    MASTER_PID=`find_master_pid $HOST`
    if $MASTER_PID
      then
        if `find_child_pid`
          echo Connection to $HOST in use: not terminating
        else
          kill -SIGHUP $MASTER_PID
        fi
    ssh -TMNf $HOST

Вы можете просто использовать

ssh -o ControlPath=$socket -O check 

для каждого открытого вами сокета $ (легко, если вы храните их в одном каталоге).

Это возвращает 255, если проверка не удалась (соединение больше не активно), другое значение, если оно прошло. Возможно, вам также потребуется указать имя хоста, но ничего, что вам не даст awk на $ socket :)

@ Ответ Реника не сработал для меня. См. Ниже, что было сделано.


Это работает для меня, используя только файл сокета для мастера управления:

$ ssh -o ControlPath=~/.ssh/<controlfile> -O check <bogus arg>

НОТА: Вы также можете использовать ssh -S ~/.ssh/<controlfile> ... а также, что является немного более короткой формой вышеупомянутого.

пример

Вот пример, когда я уже установил соединение с удаленным сервером:

$ ssh -S ~/.ssh/master-57db26a0499dfd881986e23a2e4dd5c5c63e26c2 -O check blah
Master running (pid=89228)
$

И при отключенном:

$ ssh -S ~/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74 -O check blah
Control socket connect(/Users/user1/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74): No such file or directory
$

Если бы он все еще был подключен, это заставило бы его немедленно выйти:

$ ssh -S ~/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74 -O exit blah
Exit request sent.
$

Мне непонятно, но может показаться, что это ошибка в ssh что в конце требуется дополнительный аргумент, хотя blah не имеет смысла в контексте используемых мной переключателей.

Без него я получаю следующее:

$ ssh -S ~/.ssh/master-57db26a0499dfd881986e23a2e4dd5c5c63e26c2 -O check
usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]
           [-D [bind_address:]port] [-E log_file] [-e escape_char]
           [-F configfile] [-I pkcs11] [-i identity_file]
           [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec]
           [-O ctl_cmd] [-o option] [-p port]
           [-Q cipher | cipher-auth | mac | kex | key]
           [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port]
           [-w local_tun[:remote_tun]] [user@]hostname [command]

Информация о версии

OSX
$ ssh -V
OpenSSH_6.9p1, LibreSSL 2.1.8
CentOS 7.x
$ ssh -V
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips  26 Jan 2017

Я подтвердил, что в обеих этих версиях требовался дополнительный ложный аргумент.

Ссылки

Я написал утилиту, которая упрощает управление SSH-соединениями ControlMaster. Это называется cmc: TimidRobot / cmc: ControlMaster Controller - упрощает управление SSH-соединениями ControlMaster.

Мой нынешний подход - использовать lsof чтобы найти сокеты Unix. Если я знаю целевое имя файла, указанное ControlPath Я могу искать основной процесс так:

function find_master_pid() {
  lsof -a -U -u $USER -c ssh | grep $CM_DIR/$RUSER@$HOST | sed 's/^ssh *//' | cut -d' ' -f1 | sort -u
}

Это даст мне PID (к сожалению, указание имени файла сокета unix непосредственно в lsof не работает, иначе я мог бы просто попросить его вывести мне pid с участием -f; следовательно sed и cut)

Найти дочерний процесс сложнее. Главный процесс открывает новый сокет для каждого дочернего процесса, подключенного к стандартному файлу. Дочерний процесс содержит сокет, просто помеченный socket. Однако индексный дескриптор, возвращаемый lsof на единицу меньше, чем соответствующий сокет главного процесса. Таким образом, следующее обнаруживает дочерние процессы, которые подключены к главному процессу (для этого требуется $MASTER_PID проверить против)

function find_child_pid() {
  for CHILD_PID in `lsof -a -U -u $USER -c ssh | grep socket | sed 's/^ssh *//' | cut -d' ' -f1 | sort -u`
    do
      CHECK_PID=0
      for NODE in `lsof -a -U -u $USER -p $CHILD_PID -F i | grep ^i | sed 's/i//'`
        do
          MASTER_NODE=$((NODE+1))
          CHECK_PID=`lsof -a -U -u $USER -p $MASTER_PID | grep $MASTER_NODE | wc -l`
          [[ $CHECK_PID == 1 ]] && echo $CHILD_PID
        done
    done
}