Предыстория


В связи с введением в нашей стране блокировок некоторых ресурсов (не будем показывать пальцем), понадобилось мне реализовать к ним доступ через VPN. К слову говоря, пользуюсь я этими ресурсами не так часто, но пользуюсь. И казалось бы, что проще. Есть сегодня целая куча различных сервисов предоставляющих VPN доступ.

Однако платить за сервис несколько десятков долларов и пользоваться им несколько раз в месяц я посчитал нецелесообразно. Тогда мой выбор пал на бесплатные VPN. Одним из таких является сервис vpnbook. Для моих требований его предостаточно, но вот незадача — пароль для доступа к VPN по PPTP периодически меняется. И при каждой его смене заходить на сайт копировать его и настраивать соединение на роутере — честно говоря лень. А говорят, что «лень – двигатель прогресса». В моем случае это так. Надо что-то делать…

Я подумал, а почему бы мне не парсить со страницы пароль и автоматически обновлять параметры соединения на моем Mikrotik. Почему только пароль? Ну так на vpnbook адреса серверов достаточно постоянны и я использую один а логин всегда один и тот же — vpnbook. Итак, приступим.

Часть про PHP — простенький парсер


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

При парсинге я использовал библиотеку «PHP Simple HTML DOM Parser». Её можно скачать по ссылке. И для начала нам конечно же нужно её подключить:

include "simple_html_dom.php";

Далее для того чтобы получить содержимое страницы vpnbook.com/freevpn будем использовать cURL. Пример как его использовать я взял с сайта php.net и обернул в функцию:

function url_get_html($url){
    // инициализируем cURL
    $ch = curl_init();
    // устанавливаем url с которого будем получать данные
    curl_setopt($ch, CURLOPT_URL, $url);
    // устанавливаем опцию чтобы содержимое вернулось нам в string
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    // выполняем запрос
    $output = curl_exec($ch);
    // закрываем cURL
    curl_close($ch);
    // возвращаем содержимое
    return $output;
}

Далее, используя возможности библиотеки «PHP Simple HTML DOM Parser», нам нужно вытащить пароль из содержимого страницы. Просмотрев исходный код страницы, можно увидеть, что пароль находится в последнем элементе списка в теге strong.

Кусочек исходного кода страницы
...
</div>
<p>PPTP (point to point tunneling) is widely used since it is supported across all Microsoft Windows, 
Linux, Apple, Mobile and PS3 platforms. It is however easier to block and might not work if your ISP or 
government blocks the protocol. In that case you need to use OpenVPN, which is impossible to detect or block.</p>

<ul class="disc">
    <li><strong>euro217.vpnbook.com</strong></li>
    <li><strong>euro214.vpnbook.com</strong></li>
    <li><strong>us1.vpnbook.com</strong> <span class="red">...</span></li>
    <li><strong>us2.vpnbook.com</strong> <span class="red">...</span></li>
    <li><strong>ca1.vpnbook.com</strong> <span class="red">...</span></li>
    <li><strong>de233.vpnbook.com</strong> <span class="red">...</span></li>
    <li>Username: <strong>vpnbook</strong></li>
    <li>Password: <strong>qedE3ha</strong></li>
</ul>

<div><strong><span class="green"> More servers coming. Please Donate.</span></strong></div>
...


Почему бы не получить все теги strong из первого списка на страницу и из последнего не получить пароль? Делаем:

// URL с которого будем парсить пароль
$url = "http://www.vpnbook.com/freevpn";
// получаем DOM
$html = str_get_html(url_get_html($url));
// находим необходимые элементы к первом списке с классом "disc"
$items = $html->find(".disc", 0)->find("strong");
// пароль находится в последнем
$pswd = end($items);
// выводим пароль
echo $pswd->innertext;

Итак парсер готов. Осталось его выложить на сервер.

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

include "simple_html_dom.php";

function url_get_html($url){
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $output = curl_exec($ch);
    curl_close($ch);
    return $output;
}

$url = "http://www.vpnbook.com/freevpn";
$html = str_get_html(url_get_html($url));
$items = $html->find(".disc", 0)->find("strong");
$pswd = end($items);
echo $pswd->innertext;


Часть про Mikrotik — скрипт для создания VPN подключения


Парсер готов и представим, что он доступен по адресу vpn.pswd.tk. Теперь нам нужно на Mikrotik (у меня hap lite) написать скрипт, который будет обращаться к нашему парсеру, получать от него пароль и пересоздавать VPN подключение. Покопавшись в документации Mikrotik, я нашел необходимый мне функционал, а именно с помощью /tool fetch можно сделать запрос по URL и содержимое поместить в текстовый файл, после чего считать его содержимое в переменную. Вот полный код скрипта:

/tool fetch url="http://vpn.pswd.tk/" mode=http dst-path="vpn_pswd.txt";
:delay 2s
:local password [/file get vpn_pswd.txt contents]
/file remove vpn_pswd.txt;
/interface pptp-client remove [/interface pptp-client find name=pptp-out1]
/interface pptp-client add name=pptp-out1 user=vpnbook password=$password connect-to=us1.vpnbook.com disabled=no

Немного разберем, что есть что. Первой строчкой мы делаем запрос к нашему парсеру и ответ в виде пароля записываем в файл vpn_pswd.txt. Далее, как несложно догадаться, у нас происходит задержка в 2 секунды. Для чего? Дело в том, что роутеру для выполнения запроса и создания файла требуется некоторое время и если не сделать задержку, то следующая команда может попросту не считать в переменную значение из файла (т.к. его на тот момент еще нет). Далее, после записи значения в переменную, мы удаляем созданный файл — он нам уже не нужен. Потом удаляем созданное VPN подключение и создаем новое.

Остается только добавить в планировщик запуск этого скрипта через какой-нибудь (на ваш выбор) промежуток времени. Делается это в разделе System/Scheduler. Если допустим наш скрипт называется «through_vpn_list», то тогда вот этой командой мы создадим задание для запуска скрипта каждые 6 часов:

/system scheduler add name=schedule1 interval=6h on-event="/system  script  run  through_vpn_list"

Итоги


Мы получили возможность автоматически создавать VPN подключение, используя пароль от бесплатного сервиса. Как использовать это подключение — это уже ваше решение. Например, можно настроить роутинг на основе политик, чтобы VPN подключение использовалось только для определенного списка сайтов и ресурсов. Так например у меня и реализовано. Прикладываю ссылку на документацию, по которой это можно сделать.

Конечно, это решение, скорее всего не самое лучшее. И здесь можно много чего улучшать. Например, что если поменяется верстка? Уже не будет работать парсер. Поэтому нужно подумать об более универсальном подходе к получению пароля. Но цель была достигнута и такая связка прекрасно работает.

P.S. Пожалуйста пишите комментарии, что не так, что можно улучшить. Как написано: «Без доверительного разговора планы расстроятся, а при множестве советников будет успех».
Поделиться с друзьями
-->

Комментарии (12)


  1. redmanmale
    13.09.2016 18:45
    +1

    Далее для того чтобы получить содержимое страницы vpnbook.com/freevpn будем использовать cURL.

    Как вариант, у vpnbook есть твиттер, где публикуется новый пароль.


    1. Helldar
      13.09.2016 18:58

      В этом случае не придется ли использовать Twitter API для более правильного решения? Как считаете?


      1. redmanmale
        14.09.2016 13:40
        +1

        Правильнее использовать API, безусловно.
        Вопрос в необходимости аккаунта и написании обвязки для авторизации.


  1. Helldar
    13.09.2016 19:26

    Нагуглил сервис с халявными VPN. Только там сертификаты используются.
    Если заморочиться, можно его заюзать.

    P.S.: А по L2TP/IPsec и не нужен сертификат. Пруф.


    1. 12pz21
      13.09.2016 19:51

      Спасибо, возьму на заметку.


      1. Helldar
        14.09.2016 03:10

        Кстати, вчера перед сном заюзал подключение, настроенное по линку, где пруф скидывал — микротик зацепился без всяких.
        Дальше не юзал, в сон клонило. Сегодня вечером дома гляну да отпишу в комментах о результате.
        В планах — основной трафик бросать на прямую, а нужный — через туннель)
        Если важна версия, микротик у меня RB951G-2HnD.


  1. vvsvic
    13.09.2016 20:59

    Ну вот, теперь и vpnbook скоро начнет пароли с помощью картинок выдавать. :(


  1. iluvar
    13.09.2016 21:19
    +2

    Отлично сделали.

    По части микротика, можно сократить часть

    /interface pptp-client remove [/interface pptp-client find name=pptp-out1]
    /interface pptp-client add name=pptp-out1 user=vpnbook password=$password connect-to=us1.vpnbook.com disabled=no

    до

    /interface pptp-client set pptp-out1 password=$password


    1. 12pz21
      13.09.2016 21:50

      Да, точно. Спасибо. Так даже меньше будет проблем с другими настройками на роутере, завязанными на VPN подключение (пересоздавать ничего не придется)


  1. stanr
    13.09.2016 22:10

    Спасибо :) Сам использую этот сервис, вместе в последними изменениями (позволяющими микротику самому подтягивать ip адреса в списки адресов по домену)(6.36 * firewall — allow to add domain name to address-lists (dynamic entries for resolved addresses will be added to specified list);) — идеальное решение, пол года не доходили руки этот скрипт самому сделать :)


  1. LumberJack
    15.09.2016 07:55

    Сделал всё по инструкции, добавил скрипт

    /ip firewall mangle add chain=prerouting src-address=192.168.88.0/24 content=facebook action=mark-routing new-routing-mark=Through_VPN
    /ip route add dst-address=0.0.0.0/0 gateway=«pptp-out1» Routing-Mark=Through_VPN
    /ip firewall nat add chain=srcnat src-address=192.168.88.0/24 out-interface=«pptp-out1» action=masquerade

    Интерфейс поднялся, данные фильтруются, но на facebook не заходит. Ping — 100% потерь
    Что я делаю не так?


    1. 12pz21
      16.09.2016 10:26

      Лист адресов заполнили?
      /ip firewall address-list add list=Through_VPN address=www.facebook.com
      А также его нужно указать в mangle (dst-address-list)
      Или, если хотите весь трафик через VPN пустить, то поставьте default route в pptp подключении.