Яндекс.Метрика

    Ни о чём

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

    Всем хорош 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

    Назначим пароль:

    $ 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.reghttp://www.tightvnc.com/portable/
    start winvnc.exe -run
    wget 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-серверу, с указанным номером порта)

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