November 2021

S M T W T F S
 123456
78910111213
1415161718 1920
21222324252627
282930    

Style Credit

Expand Cut Tags

No cut tags
Friday, February 21st, 2020 04:03 pm
По итогам обсуждения у Витуса (1 серия, 2 серия) собрал и причесал:

source_ssh_auth:
fix_ssh_auth_sock () {
    if [ -e "$HOME/bin/fixssh" ]; then /bin/rm -f "$HOME/bin/fixssh"; fi
    if [ -S "$SSH_AUTH_SOCK" -a ! -L "$SSH_AUTH_SOCK" ]; then
        local new_ssh_auth_sock_dir
        new_ssh_auth_sock_dir="$HOME/.ssh/auth_sock"
        local new_ssh_auth_sock
        new_ssh_auth_sock="$new_ssh_auth_sock_dir/auth_sock.$(hostname)"
        if [ ! -d "$new_ssh_auth_sock_dir" ]; then
            mkdir -p "$new_ssh_auth_sock_dir" || return
        fi
        ln -sf "$SSH_AUTH_SOCK" "$new_ssh_auth_sock" || return
        SSH_AUTH_SOCK="$new_ssh_auth_sock"
        export SSH_AUTH_SOCK
    fi
}

case "$DISPLAY" in
    # don't run fix_ssh_auth_sock if logged in locally in X
    # because otherwise you'll lose connection to local ssh agent
    # after first remote or terminal login to this host
    :*) ;;
    *) fix_ssh_auth_sock ;;
esac


Что делает. Если видит в переменной SSH_AUTH_SOCK сокет ssh-агента (но не симлинк на него — поэтому ! -L), делает на него симлинк с well-known именем. После чего переставляет переменную SSH_AUTH_SOCK.

Единственная переменная часть в имени — hostname. Защита от проблем, возникающих в случае с NFS-mounted home.

Что позволяет. Типичная ситуация: с хоста A, где агент, идем с форвардом агента на хост B, запускаем там screen или tmux, и оттуда ходим на хосты C, D и т.д. Если не выполнить fix_ssh_auth_sock, то после первого detach, по любой причине, $SSH_AUTH_SOCK внутри screen останется негодным навсегда. А он случайный. А если выполнить, то после перелогина и подсоединения к сессии он снова станет годным. Будет через симлинк указывать на новый сокет.

Запускается... Во-первых, не запускается, а читается. "." (source), в смысле. Потому что надо переставить переменную. У меня из .zprofile, а остальным рекомендуется .profile или .bash_profile. Синтаксис намеренно выдержан таким, чтобы можно было запускать даже из dash.

Не надо запускать это из НЕинтерактивного шелла — агент отвалится после завершения команды. Честно говоря, маны на bash и dash мутны в части того, выполняется ли .profile из логинного, но неинтерактивного шелла. Подозреваю, что нет, но экспериментируйте себе сами.

.zlogin:
if [ -n "$SSH_CONNECTION" ]; then exec screen -xRR; fi


Что делает. При интерактивном логине по ssh молча запускает screen в режиме «если есть запущенная сессия, подцепиться к ней (к самой свежей по времени создания, если их несколько), НЕ отцепляя других возможных клиентов той же сессии; если ее нет, создать и подцепиться». Согласно man screen, именно с этими ключами screen запускается, если указать его в качестве логинного шелла.

Что позволяет. Не попадать в ситуации, когда надо бы отцепиться от сервера (положить спать ноутбук, с которого зашли), а команда на сервере оказалась слишком долгоиграющей, и прерывать ее не хочется. Или в ситуации, когда и не стал бы отключаться, да канал упал, не спросив. Общий принцип: зашел на удаленную машину — запусти screen.

Запускать. У меня из вышеуказанного .zlogin. У кого .profile или .bash_profile, оттуда последней командой.
Tags:
Friday, February 21st, 2020 03:47 pm (UTC)
Интересно, спасибо!

Мне почему-то это редко нужно. Хотя на удалённые сервера с отваливающимися соединениями я хожу постоянно.

Но раз есть готовое решение — возьму, пожалуй, на вооружение.

Меня смущает exec — если у меня проблемы с запуском screen, я потом смогу зайти интерактивно и починить? Не отключит exec мне возможность залогиниться?
Friday, February 21st, 2020 04:00 pm (UTC)
можно без экзека, один лишний процесс будет, ничему мешать не должно.

security implications вроде бы тоже не просматривается
Friday, February 21st, 2020 06:02 pm (UTC)
Без эзека после отцепления screen сессия не завершится. И ты опять попадешь в shell на удаленной машине, но уже без screen.

Friday, February 21st, 2020 06:17 pm (UTC)
ммм, и в чём проблема, если у тебя не кончаются ttys?
Friday, February 21st, 2020 06:19 pm (UTC)
Проблема в том, что ты можешь по ошибке запустить в этом окне долгоиграющий процесс. А скрина там уже не будет.
Friday, February 21st, 2020 06:23 pm (UTC)
а, это да. но watch (если там был терминал) или по крайней мере kill (если не было) уж точно ж есть

да, немножко ядерное оружие, но
Friday, February 21st, 2020 06:41 pm (UTC)
А ведь вся эта возня затевается для того,чтобы запущенный на удаленной машине процесс всегда попадал в сессию screen и можно было не бояться что его прибюьт SIGHUP-ом если коннект прервется.

А без exec у тебя оказывается достаточно большая вероятность что на экране будут валяться окна удаленных сессий без screen.
Friday, February 21st, 2020 04:01 pm (UTC)
я б кстати написал просто

[ -n "$SSH_CONNECTION" ] && screen -xRR

;-P
Friday, February 21st, 2020 06:05 pm (UTC)
Я так и написал. Но после того как набрал exit внутри screen понял, что был неправ.
Friday, February 21st, 2020 06:24 pm (UTC)
стой-стой. моё написание в точности идентично твоему

или я в чего-то не увидел?
Friday, February 21st, 2020 06:29 pm (UTC)
Я когда реализовывал у себя эту конструкию, сначала сделал как предлагаешь ты.
Но после того как попробовал завершить удаленную сессию, понял что это неправильно, и надо делать как предлагает Артем.
Friday, February 21st, 2020 06:50 pm (UTC)
прости.

я натурально не вижу семантической разницы (ну, sirca exec)
Friday, February 21st, 2020 10:47 pm (UTC)
В крайнем случае ssh -t $host bash --norc
Friday, February 21st, 2020 06:04 pm (UTC)
А может мы зря уперлись в создание сокета в ${HOME}?
Есть /tmp/user/$(id -u), есть /run/screen/S-${LOGNAME}
Эти места оказываются заведомо локальны для машины и не то чтобы совсем заведомо, но в типичной ситуации writable для юзера.
Friday, February 21st, 2020 06:21 pm (UTC)
это чуть специфично для разных систем. для фри это вообще /tmp/screens/S-${user}/
Friday, February 21st, 2020 06:43 pm (UTC)
Да, и как-то штатного способа заставить screen рассаазать какой у него здесь путь, причем наружу, а не внутрь, я что-то не вижу.
Friday, February 21st, 2020 06:51 pm (UTC)
да, и это тоже анти-портабельная жопа
Friday, February 21st, 2020 06:52 pm (UTC)
и если ты в контейнере, из хоста тоже по-разному!
Saturday, February 22nd, 2020 06:24 am (UTC)
Если это настоящий контейнер, а не просто chroot, то какая разниа - все равно с хоста не дадут писать/читать сокет, созданный в контейнере.
Saturday, February 22nd, 2020 06:25 am (UTC)
/tmp/user/$(id -u), насколько я помню, создает systemd. И прописывет это в ${TMPDIR}.
Saturday, February 22nd, 2020 07:20 am (UTC)
mktemp /tmp/${USER}.${`hostname`}

чтобы от луркеров защититься

и в хомяк его имя линком (поэтому в оригинале хост)
Friday, February 21st, 2020 10:59 pm (UTC)
А в zsh нет $HOSTNAME — вместо $(hostname)?
Tuesday, May 12th, 2020 09:24 pm (UTC)
export лишний. SSH_AUTH_SOCK к этому моменту уже проэкспортирован, а второй раз незачем.

Хуже от этого не будет, конечно.

Или в zsh другие правила переэкспортирования переменных?
Tuesday, May 12th, 2020 10:40 pm (UTC)
exec screen -xRR у меня падает. Запускается и сразу на выход. Я подумал и стал подозревать, что проблема в том, что внутри screen тоже запускается .profile, в котором запускается exec screen; screen это отлавливает и прекращает цикл.

Поставил защиту: [ -n "$SSH_CONNECTION" -a -z "$STY" ] && exec screen -xRR. Теперь screen запускается, но перестал работать rsync. Похоже, у меня неинтерактивный ssh всё равно запускает .profile. Поставил ещё одну защиту, от неинтерактивного использования: -t 0. Пока всё работает. В целом конец моего .profile теперь выглядит так:

[ -n "$SSH_CONNECTION" -a -z "$STY" -a -t 0 ] && which screen >/dev/null 2>&1 &&
   exec screen -xRR -S default
Wednesday, May 13th, 2020 07:24 am (UTC)
-t 0 не достаточно — эта защита не срабатывает в ситуации ssh -t host command. Пришлось усилить защиту — добавил проверку флага i (интерактив) в переменной $-:

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return ;;
esac

# Stop if non-interactive shell
[ -z "$PS1" ] && return

if [ -n "$SSH_CONNECTION" -a -z "$STY" -a -t 0 ] &&
   which screen >/dev/null 2>&1
then
   exec screen -xRR -S default
fi
Thursday, May 14th, 2020 07:46 am (UTC)
Две проверки просто так, без причины. Я их натаскал когда-то из разных мест в .bashrc, а теперь вот скопировал в .profile :-)