5

У меня есть ssh-туннель, прослушивающий локальный порт, скажем, 8888, открытый с удаленного компьютера с помощью ssh -R 8888:localhost:80 myuser@myhost . Мне нужно написать скрипт для "myuser" на "myhost", который закроет этот туннель.

Сценарий будет выполнен "myuser" на "myhost". Это не будет выполнено рутом, и это не будет в состоянии sudo.

Один из подходов состоит в том, чтобы найти PID процесса, прослушивающего 8888 с помощью lsof или netstat, а затем завершить процесс. Тем не менее, как lsof, так и netstat отказываются давать мне PID без использования sudo. С netstat я просто получаю - вместо "PID/Program name" без sudo.

Есть ли способ узнать PID процесса, прослушивающего данный порт без привилегий root? Процесс прослушивания на этом порту выполняется под тем же пользователем, что и мы. Или есть какой-то другой способ закрыть ssh-туннель снаружи?

Обратите внимание, что использование escape-последовательности ssh для сброса соединения не является решением, поскольку мы не находимся в туннеле. Наш скрипт должен запускаться отдельно от туннеля на одном хосте одним и тем же пользователем.

Также обратите внимание, что просто запустить killall sshd - это не решение, поскольку оно уничтожит все другие ssh-соединения, не только это.

Этот вопрос не является дубликатом многих похожих вопросов, потому что все их принятые ответы, которые я нашел, требуют привилегий root или просто убивают все ssh-соединения.

На хосте "myhost" работает Ubuntu 12.04.5.


Изменить: резюме обсуждения по запросу @Jakuje:

  • @Patrick предложил подход использовать setuid или модифицировать /etc/sudoers чтобы позволить пользователю запускать скрипт с привилегиями root без полного sudo. Хотя для setuid нам нужно написать бинарный файл вместо скрипта. Однако разрешение пользователю запускать сценарий с привилегиями root может представлять потенциальную угрозу безопасности. И все же это решение не распространяется на случай, когда пользователь вообще не имеет root-доступа, поэтому он не может изменить /etc/sudoers . Если @Patrick напишет это в качестве ответа, я определенно проголосую, но пока не буду отмечать, что он принят.

  • @EricRenouf обнаружил, что sshd сокращает сокет для пользователя, поэтому пользователь не может использовать /proc/*/fd чтобы найти процесс, имеющий сокет. Наверное, поэтому ни lsof, ни netstat не показывают этого.

Больше идей:

Как обнаружил @EricRenouf, вероятно, нет способа получить PID sshd по номеру открытого порта сокета или по индексу. Но мне любопытно, если нет другого трюка, как найти этот sshd PID или как сказать ему, чтобы закрыть соединение. Возможно как-то напрямую с sshd.

Например, если я включил режим отладки sshd -d он записал бы, какой процесс sshd открыл туннель к какому порту в /var/log/auth.log который читается пользователем. Таким образом, скрипт может проанализировать журнал и найти там PID. Но запуск режима отладки sshd не очень хорошая идея. На самом деле существует простой патч для sshd для регистрации открытых туннелей даже без режима отладки. Но я не уверен, что запуск пропатченного sshd также будет хорошей идеей.

Есть ли другой трюк?

1 ответ1

2

Начните с настройки пользовательского ключа SSH для подключения к "myhost". Затем отредактируйте файл .ssh/authorized_keys на "myhost", чтобы родительский PID оболочки записывался в файл:

command="echo $PPID > tunnel.pid; bash" ssh-rsa AAA...

Вы можете настроить некоторые другие параметры безопасности и / или вы можете написать собственный скрипт, чтобы просто написать PID и зависнуть. Принцип одинаков в любом случае.

Если у вас есть PID процесса, который поддерживает сессию SSH, это просто вопрос сценариев ...

kill `cat tunnel.pid`

... завершить процесс, закрыв тем самым сессию SSH.

Обратите внимание, что вы можете использовать флаг -i для команды ssh чтобы указать закрытый ключ для подключения.

Редактирование: уничтожение процесса оболочки не приведет к закрытию туннеля, если есть активные соединения, поэтому мы уничтожаем родительский процесс SSH.

Редактирование: Хотя мое первое желание при использовании любого автоматического SSH-соединения - использовать SSH-ключи, тот же процесс можно эмулировать с помощью:

ssh -R 8888:localhost:80 myuser@myhost 'echo $PPID > tunnel.pid; for ((;;)); do sleep 1; done'

Вы также можете заменить скрипт, который проверяет некоторые другие критерии, чтобы решить, когда прекратить сам. Это, вероятно, более чистый способ справиться с этим.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .