Pull to refresh

Аналог Teamviewer из VNC, SSH и суперклея

Reading time4 min
Views55K
Всем хорош teamviewer, вот только в коммерческих целях он какой-то не бесплатный, о чем не устает напоминать… Да и вообще, не хорошо нарушать лицензию.

Но удобство запуска quick support впечатляет — клиент запускает маленькую программку, диктует циферки по телефону и вуаля, мы видим его рабочий стол. Никаких VPN, никаких пробросов портов и прочей предварительной настройки. Удобно же?

В качестве бесплатного аналога вполне подходит VNC, с call-back подключением вполне приемлемо, да вот только когда клиентов много, и компьютер к которому цепляются тоже не один начинаются те же проблемы (хотя и более решаемые). Идея teamviewer лично мне нравится больше. А если нравится, почему бы не сделать свою реализацию…



Сразу оговорюсь, предлагаемое решение, еще даже и не решение совсем, реализация задумки была выполнена «на попробовать», но вполне доказала свою работоспособность, а улучшательства и удобства — можно допилить по ходу времени.

Итак, за основу возьмём winvnc (tightvnc), прикрутим к нему реверсивный SSH-туннель, а определять клиента будем, например по номеру порта. Нам потребуется:
OpenSSH сервер (на линуксе, например), web-сервер (с php в моем случае).
Клиент будет использовать собс-но winvnc (я взял из комплекта tightvnc-portable) и консольный клиент SSH plink из пакета Putty.

В альфа-версии нашего клиента удаленной поддержки не будет ничего лишнего (да и не лишнего тоже много чего не будет), и Т.З. для сервера будет выглядеть примерно так:

  • На сервере должен быть некий бесправный пользователь, без права входа в систему, но с возможностью поднимать реверсивные туннели. Прямые туннели так же должны быть ограничены.
  • Сервер как-то должен сообщать клиенту данные о туннеле, адрес, свободный порт из некоего диапазона.


Для клиента:
При запуске клиент при должен запросить с сервера данные о туннеле.
Запускать winvnc с заранее определенными настройками
Поднимать SSH-туннель с полученными настройками.

Приступим:

Не буду углубляться в вопросы запуска apache2+php+OpenSSH, предположим, что все это уже имеется.
Добавим пользователя vnc:

$ sudo useradd -M -s /bin/false vnc

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

Назначим пароль:
$ sudo passwd vnc

Пароль любой, он все равно будет лежать где-то в открытом виде.

В sshd_config (/etc/ssh/sshd_config) разрешим открывать порты на всех сетевых интерфейсах, добавив опцию:
GatewayPorts=yes


Без неё туннель откроется на адресе 127.0.0.1 (со стороны сервера) и без дополнительных шаманств его использовать удаленно не получится. Остается перезапустить OpenSSH

$ sudo service ssh restart

Передавать настройки клиенту придумалось в виде cmd скрипта, который запустит plink и оповестит клиента о волшебной циферке которую нужно сообщить. Этим займется скрипт на PHP (или на чем будет удобно) вида:

<?php
$server = 'mysshserver.com'; // адрес OpenSSH сервера
$user = 'vnc'; // Логин созданного пользователя
$password= '123'; // Пароль от созданного пользователя
$ssh_port=22; //Порт на который слушает SSH
$vnc_port=11111; //порт на котором будет висеть VNC-сервер
$port_start = 40000; //диапазон выдаваемых портов
$port_end = 50000;
$ports = NULL;
//Определяем занятые порты
$r =  exec("netstat -lnt4 | tail -n +3 | awk 'BEGIN{FS=\"[: ]+\"}{print $5;}' | sort -n", $ports);
//Находим свободный из заданного диапазона
do {
        $port = rand($port_start, $port_end);
        if(!in_array($port, $ports)) break;
} while (1);
//выдаем cmd-скрипт
header("Content-type: text/plain;");
echo "@echo off\r\n";
echo "title Port number is: $port\r\n";
echo "start /MIN cscript mb.vbs \"Port number is: $port\"\r\n";
echo "plink.exe  -N -R $port:localhost:$vnc_port -P $ssh_port -pw $password -l $user -batch $server \r\n"
?>


И добавим разрешения для фаерволла:
#разрешение уже установленных соединений
iptables -A OUTPUT   -m state --state RELATED,ESTABLISHED -j ACCEPT
#запрещение всех остальных пользователю vnc
itpables -A OUTPUT  -m owner --uid-owner `id -u vnc` -j REJECT
# разрешение соединений в диапазон 40000-50000
itpables -A INPUT -p tcp --dport 40000:50000 -j ACCEPT
Остальные настройки (политика по-умолчанию, разрешение SSH, HTTP -трафика, для при):
itpables  -P INPUT    DROP
itpables -A INPUT -p tcp —dport 22 -j ACCEPT
itpables -A INPUT -p tcp —dport 80 -j ACCEPT


Теперь приступим к сборке пакета для клиента. В него войдет:
winvnc (повторюсь, я взял из пакета tightVNC portable) и необходимые библиотеки
plink с сайта putty
wget for windows (binaries и dependencies)
reg-файлы настроек для winvnc и настройки для plink. Последний очень хочет одобренный ключ SSH в реестре и нет никакой возможности не интерактивно добавить его.

Для получения заветных кусков реестра, запускаем Putty цепляемся к нашему SSH-серверу, принимаем ключ и экспортируем реестр:

reg export HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\SshHostKeys keys.reg


Точно также поступаем с настройками winvnc: запускаем на стендовом компьютере,
в настройках задаем:
  1. Пароль или пустой, по вкусу, на вкладке Server,
  2. там же устанавливаем номер порта я поставил 11111 (используется в только PHP-скрипте).
  3. На вкладке Administration разрешаем loopback соединения, в случае пустого пароля — разрешаем их использование.
  4. Ну и выключаем HTTP сервер, он в нашем случае не используется.

Применяем, закрываем и экспортируем:
reg export HKEY_CURRENT_USER\Software\ORL\WinVNC3 winvnc.reg


Добавим vb-скрипт, который будет выводить окно сообщения заданным текстом:
mb.vbs:
Set objArgs = WScript.Arguments
messageText = objArgs(0)
MsgBox messageText


И самый главный скрипт, который все свяжет:
runme.cmd:

winvnc.exe -kill
reg import host-key.reg
reg import winvnc.reg
start winvnc.exe -run
wget http://mysshserver.com/script.php -O tunnel.cmd && tunnel.cmd
winvnc.exe -kill


в нем пришибаем winvnc (вдруг уже работает?),
импортируем куски реестра,
запускаем winvnc
скачиваем скрипт и если скачался — запускаем его.

Остается сложить все вышеописанное в одну папку и запаковать в SFX архив, с запуском этого скрипта после распаковки: для WinRAR SFX как-то так:
Silent=1
Path=%TEMP%\support
SavePath
Setup=%TEMP%\support\runme.cmd


и можно отдавать клиенту. При запуске, тихо и незаметно распакуется архив, запустится скрипт runme.cmd, который настроит winvnc, plink, скачает скрипт запуска туннеля, запустит его и оповестит клиента о номере порта.
Как и в случае с teamviewer — клиент сообщает его, и можно подключаться (уже к нашему SSH-серверу, с указанным номером порта)

В итоге имеем:
  • Клиент может сидеть за NAT
  • VNC Viewer так же может быть за NAT
  • Единственное, что необходимо для подключения к клиенту — номер порта, который продиктует клиент.


Теперь о планах на будущее:
  1. Убрать тяжелый wget и вообще все скрипты переписать на VBS
  2. Сделать web-интерфейс для отслеживания подключенных клиентов и возможность скачать VNC-файл для быстрого подключения.
  3. Что еще?
Tags:
Hubs:
+43
Comments56

Articles

Change theme settings