Использование Утилит Timeout И Strace Для Отслеживания Бездействия Пользователя И Прекращения Соединения С Shellinabox.

Недавно я исследовал, какие существуют решения для реализации прокси-сервера web-ssh. Суть задачи — дать пользователям возможность подключаться к произвольному SSH-серверу через веб-интерфейс.

Обычно решения web-ssh предназначены для подключения к серверу, на котором они развернуты, но для моей цели я хотел, чтобы пользователь мог указать IP, порт, имя пользователя и пароль (или ключ) и подключиться к произвольному серверу.

.

Мне не удалось найти такое решение сразу.

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

Однако для открытого пакета Shellinabox я нашел решение по адресу блог на немецком языке, который я решил довести до нужного мне уровня.

В результате получается красивый Docker-контейнер, который можно найти по адресу: GitHub скоро Докерхаб , который решает все необходимые проблемы.

Но статья не об этом, а о сопутствующем Python-коде, который мне пришлось написать.

Дело в том, что мне не понравилось то, что если пользователь открыл web ssh и куда-то зашёл, то сессия зависала на неопределённое время, что на мой взгляд недопустимо.

Это приводит к следующим негативным последствиям:

  1. ресурсы терминального прокси-сервера используются неэффективно, поскольку он вынужден обслуживать неиспользуемые сессии;
  2. Необслуживаемое окно с открытым ssh в браузере вызывает чувство тоски и уязвимости.

В общем, я решил, что хочу добиться того, чтобы Shellinabox разрывал соединение, если пользователь в течение нескольких минут ничего не писал в консоль (stdin) и на stdout не поступали данные.

Довольно долгий поиск в Google показал мне, что цели можно достичь с помощью команды timeout и strace. Команда тайм-аута была для меня новой; его цель — гарантировать, что процесс будет прерван по достижении определенного тайм-аута, если он не завершился сам.

Я часто использую команду strace, но обычно использую ее, чтобы выяснить, почему какая-то служба или команда не работает должным образом.

В рамках поиска того, как отслеживать активность на каналах stdin и stdout процесса, я обнаружил, что strace также может обеспечить это:

  
  
  
   

strace -e write=1,2 -e trace=write -p <PID>

В общем, эти команды были тем, что мне было нужно для осуществления моих планов.

Общая схема выглядит так:

  1. Когда открывается новое соединение, Shellinabox запускает скрипт Python;
  2. Сценарий Python запускает (разветвляет) процесс-демон для мониторинга активности процесса, который отслеживает свой собственный PID;
  3. Скрипт Python выполняет (exec) ssh (заменяя себя на ssh).

Для тех, кто хочет сразу увидеть, как работает весь скрипт, высылаю здесь .

В остальном дальше по частям.

Кратко код можно представить следующим образом.



monitor_daemon(inactivity_interval, identity_file) .

.

os.execv("/usr/bin/ssh", ["/usr/bin/ssh"] + identity_args + ["-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", "-p", str(peer_port), "%s@%s" % (peer_login, peer_ip)])

Код прост и не требует пояснений.

Вся магия внутри функции

monitor_daemon

:

def monitor_daemon(inactivity_interval, identity_file): orig_pid = os.getpid() try: pid = os.fork() if pid > 0: return except OSError as e: print("Fork #1 failed: %d (%s)" % (e.errno, e.strerror)) sys.exit(1) os.chdir("/") os.setsid() os.umask(0) try: pid = os.fork() if pid > 0: sys.exit(0) except OSError as e: print("Fork #2 failed: %d (%s)" % (e.errno, e.strerror)) sys.exit(1) if identity_file != "": time.sleep(1) os.unlink(identity_file) try: while True: proc = subprocess.Popen('timeout %d strace -e write=1,2 -e trace=write -p %d' % (inactivity_interval, orig_pid), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc.poll() counter = 0 for line in proc.stderr.readlines(): counter += 1 if(counter <= 3): os.kill(orig_pid, signal.SIGKILL) sys.exit(0) except Exception as e: pass sys.exit(0)

где нас больше всего интересует часть:

while True: proc = subprocess.Popen('timeout %d strace -e write=1,2 -e trace=write -p %d' % (inactivity_interval, orig_pid), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc.poll() counter = 0 for line in proc.stderr.readlines(): counter += 1 if(counter <= 3): os.kill(orig_pid, signal.SIGKILL) sys.exit(0)

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

Вот и все.

Решение оказалось довольно простым, но изучение доступных инструментов потребовало некоторого времени.

PS: Я не профессиональный разработчик Python, код неоптимален.

PPS: Если у кого-то есть желание улучшить код, добро пожаловать в репозиторий , с радостью приму пиар.

Теги: #linux #python #strace #ssh #shellinabox #python #разработка Linux

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.