МОДУЛЬ И МОСТ VPN ТЕХНИЧЕСКОЕ ЗАДАНИЕ ГЛОССАРИЙ Точка - в соединении Peer-to-Peer, одна из точек соединения. Локальная - та что ближе к нам; удаленная - та что дальше от нас. Мост - в данном контексте, это сервер-посредник, или backconnect-сервер, коммутирующий VPN-соединения между собой. ЦЕЛЬ Разработка комплекса, аналогичного по функциям TeamViewer в режиме VPN, состоящего из трех частей: - модуль на машине А, к которой мы хотим подсоединиться (дальний конец); - VPN-клиент на машине Б, с которой мы хотим подсоединиться к машине А и всей её локальной сети (локальный конец); - VPN-мост В, который принимает входящие VPN-соединения от А и Б и маршрутизирует их между собой (маршрутизатор, хаб). Смысл использования VPN-моста в том, что машина А как правило находится за NAT/файрволлом и напрямую к ней не подрубиться. А также потому, что могут быть закрыты входящие и исходящие TCP-порты, и поэтому нужно использовать порты наподобие 80 и 443 для исходящих соединений. Потому соединение происходит так: - А соединяется с В - Б соединяется с В - В пробрасывает маршруты между локальными точками А и Б таким образом, что Б видит А и её сеть, но не наоборот. Акцент здесь не столько на VPN, как на маршрутизацию. Нужен УДОБНЫЙ способ присоединиться к удаленной сети. Но VPN тоже нужен, т.к. незакрытый шифрованием трафик может резаться файрволлами и DPI-фильтрами. МОДУЛЬ: РЕАЛИЗАЦИЯ Модуль оформляется по правилам из документа "module_HOWTO". У модуля единственный конфиг с именем "vpnsrv". Содержимое конфига - простой текст, разделитель строк \r\n. В строке один адрес/имя сервера в формате address:port или hostname:port. Это адрес VPN-моста В. Предполагается, что модуль работает с правами администратора. При старте, модуль действует так: - дожидается получения конфига с адресами моста - случайным перебором находит рабочий мост (к которому удалось открыть соединение) - если нет рабочих мостов, выдает событие "VPN bridge failure" и далее запрашивает собственную выгрузку событием "WantRelease". - создает новое VPN-соединение к мосту В, используя штатные средства винды ("Центр управления адаптерами и общим доступом" - "Подключиться к сети"). Логином к соединению служит ParentID (см. ParentInfo в "module_HOWTO"), паролем - ParentGroup. - запускает VPN-соединение к мосту В - периодически проверяет статус соединения (можно простым пингом на адрес удалённой точки А) - при закрытии соединения, восстанавливает его - при выгрузке модуля вызовом Release(), завершает соединение и удаляет его из системы. Вообще, предлагается использовать встроенный в Windows VPN-клиент. Но нужно найти способ подавить всплывающие уведомления (balloons) из системного трея, при соединении/отсоединении. Но здесь решение за разработчиком. Штатный клиент предлагается потому, что он уже есть в ОС; если есть способ создать легковесный VPN-клиент, занимающий в готовом виде до 1 мегабайта и являющийся одной .dll (вместе с модулем), то это тоже допустимый вариант. МОСТ: РЕАЛИЗАЦИЯ Предположительно, можно организовать мост на OpenVPN. Вопросы вызывает маршрутизация. С большой долей уверенности, у машин А из разных организаций будут повторяющиеся адреса подсетей (192.168.0.х, 192.168.1.х, 10.0.х.х итд). То же самое возможно и для клиентов Б, находящихся за NAT. Поэтому, если к мосту подключится одновременно два и больше независимых клиента (Б1, Б2) и модуля (А1, А2), велика вероятность коллизии в маршрутизации между подсетями. Наивное решение - запретить работу более одной пары А/Б. Нужно найти способы обойти эту проблему. Предполагается, что есть HTTP API для управления мостом, кроме OpenVPN. В API есть следующий вызов: GET /api/session/ParentID/ParentGroup HTTP/1.1 Здесь ParentID/ParentGroup - идентификаторы (ИД) модуля А. В ответ мост посылает открытым текстом клиентский конфиг OpenVPN для клиента Б, с помощью которого можно соединиться с парным ему модулем А. При обработке запроса, мост: - запоминает ИД модуля А и заносит ИД в качестве корректного логина/пароля со сроком жизни в 3600 секунд (настройка) - генерирует сеансовый логин/пароль для парного клиента Б со сроком жизни в 3600 секунд (настройка) - генерирует конфиг OpenVPN для для парного клиента Б и отдает его вместе с HTTP-кодом 200 - если сгенерировать конфиг OpenVPN невозможно из-за недостатка данных (например, неизвестен адрес подсети модуля А, и нельзя форсировать маршрут к его подсети), мост запоминает запрос и отдает его номер (квитанцию) клиенту, до уточнения данных, вместе с HTTP-кодом 202 Accepted - HTTP-клиент периодически опрашивает готовность запроса с тем же самым URI GET /api/session/ParentID/ParentGroup HTTP/1.1 и анализирует код ответа: 200 - ответ готов 204 - в обработке 40* - ошибка обработки 50* HTTP API следует защитить простой защитой от несанкционированного доступа - скорей всего Security by obscurity - сложным неиндексируемым путем к API, либо HTTP Basic Auth. Таким образом, мост несет следующие функции: 1. авторизация модуля - Модуль должен указывать ParentID/ParentGroup в качестве логина и пароля на соединение; мост должен авторизовать модуль. Мост получает список актуальных логинов/паролей и время их жизни в секундах по HTTP API. Допустимо авторизовать только соединения с паролями из этого списка. 2. авторизация клиента - для клиента, мост генерирует сеансовый логин/пароль, а также конфиг клиента для OpenVPN и отдает их через управляющее API. ПОЛЬЗОВАТЕЛЬСКИЙ СЦЕНАРИЙ Я, как пользователь, зашел в темную админку, выбрал клиентскую сессию с КОНКРЕТНЫМ ID и группой, от имени которого я хочу работать. Я нажал в панели кнопку VPN. За кадром, на дальнем конце (А) запустился модуль VPN, получил конфиг с адресом моста и поднял к нему VPN-соединение, ЗАЛОГИНИВШИСЬ со своим ID и группой. Так мост знает, кто к нему подсоединился - ему это нужно для поиска пар соединений А и Б. Тем временем темная админка дернула веб-бекенд моста по REST API, запросив конфиг для только что поднятого соединения. Указав ID и группу бота при этом. Мост сгенерировал сеансовый логин-пароль для парного клиентского VPN-соединения, и сгенерил временный OpenVPN-конфиг (простой текстовый файл) для парного соединения. И отдал его в ответ на запрос по REST API. Темная админка отдает конфиг пользователю. Пользователь получает этот конфиг и подсовывает его клиенту OpenVPN. Подымается парное соединение со стороны пользователя на мост. Мост может связать пару соединений - конечное (А-В) и пользовательское (Б-В), потому что он знает как ID и группу бота, идентифицирующие А-В, так и сеансовый пароль юзера, идентифицирующий Б-В. Мост провешивает маршрут в таблице маршрутизации ОС. Доп.маршруты для дальних концов пары соединений уже были отданы при установке соотв.соединений. ИНСТРУКЦИЯ ПО ИСПОЛЬЗОВАНИЮ МОДУЛЯ 1. Заходим в леро, выбираем интересную нам сессию 2. Выполняем push_back код команды 62 параметры команды vpnDllstart 3. Ожидаем запуска модуля (смотрим в леро сообщения от модуля) 2020-01-16 13:25:58 vpnDll net flyAgaric Can't connect to 173.232.146.30, error 718 2020-01-16 13:25:59 vpnDll net flyAgaric VPN bridge failure алгоритм тестирования такой 1. запускаем софт на тестовой машине, даем ему развернуться 2. открываем его страничку в админке леро 3. запускаем команду push back: 62 vpnDll start 4. ждем пока модуль отреагирует и смотрим в логе админки как он отработает 5. параллельно смотрим что происходит на экране 6. ну и ищем в админке http:///admin/index.php?r=vpn%2Findex сессию, которую открыл модуль короче говоря, простой тест - модуль работает, если ты в леро его запустил командой 62 vpnDll start и получил сессию в админке впн