Настраиваем автоматическое получение пароля для VPN на Mikrotik

Предыстория


В связи с введением в нашей стране блокировок некоторых ресурсов (не будем показывать пальцем), понадобилось мне реализовать к ним доступ через 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. Пожалуйста пишите комментарии, что не так, что можно улучшить. Как написано: «Без доверительного разговора планы расстроятся, а при множестве советников будет успех».
Share post

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 18

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

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

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

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

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

      P.S.: А по L2TP/IPsec и не нужен сертификат. Пруф.
        0
        Спасибо, возьму на заметку.
          0
          Кстати, вчера перед сном заюзал подключение, настроенное по линку, где пруф скидывал — микротик зацепился без всяких.
          Дальше не юзал, в сон клонило. Сегодня вечером дома гляну да отпишу в комментах о результате.
          В планах — основной трафик бросать на прямую, а нужный — через туннель)
          Если важна версия, микротик у меня RB951G-2HnD.
        0
        Ну вот, теперь и vpnbook скоро начнет пароли с помощью картинок выдавать. :(
          +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
            0
            Да, точно. Спасибо. Так даже меньше будет проблем с другими настройками на роутере, завязанными на VPN подключение (пересоздавать ничего не придется)
            0
            Спасибо :) Сам использую этот сервис, вместе в последними изменениями (позволяющими микротику самому подтягивать ip адреса в списки адресов по домену)(6.36 * firewall — allow to add domain name to address-lists (dynamic entries for resolved addresses will be added to specified list);) — идеальное решение, пол года не доходили руки этот скрипт самому сделать :)
              0
              Сделал всё по инструкции, добавил скрипт
              /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% потерь
              Что я делаю не так?
                0
                Лист адресов заполнили?
                /ip firewall address-list add list=Through_VPN address=www.facebook.com
                А также его нужно указать в mangle (dst-address-list)
                Или, если хотите весь трафик через VPN пустить, то поставьте default route в pptp подключении.
                0
                Отличный мануал, использовал его на 200%.
                Внесу свою лепту. Переписал скрипт для mikrotik. Его нужно вызывать каждую 1 минуту. Скрипт мониторит статус pptp соединения и при разрыве связи вызывает всю процедуру запроса нового пароля, таким образом микротик не флудит попытками открытия соединение в течении нескольких часов с неправильным паролем, а переподключение делается за 1 минуту. Также тут отслеживаются ошибки on-error для fetch и file get, чтобы точнее определить, что пароль получен.
                :global VPNErr false
                :global VPNPassFile "VPNBookPass.txt"
                :global VPNBookPass
                :if (![/interface pptp-client get "pptp-out1" running]) do={
                  /interface pptp-client set pptp-out1 disabled=yes
                  :do {/tool fetch url="http://парсер.хост/vpnbookpass.php" dst-path=$VPNPassFile} on-error={:set VPNErr true}
                  :delay 2
                  :do {:set VPNBookPass [/file get $VPNPassFile contents]} on-error={:set VPNErr true}
                  :if (!$VPNErr) do={
                    /interface pptp-client set pptp-out1 password=$VPNBookPass
                    /interface pptp-client set pptp-out1 disabled=no
                  }
                }
                


                Еще рекомендую добавить отключение pptp интерфейса по разрыву связи (событие on-down) в PPP-профиль, чтобы переподключение вообще не флудило даже в течении 1 минуты. Соответственно, основной скрипт в течении 1 минуты в случае удачного получения нового пароля поднимет pptp-out1 соединение.

                add change-tcp-mss=yes name=VPNBook on-down="/interface pptp-client set pptp-out1 disabled=yes" use-compression=yes use-encryption=\
                    yes use-ipv6=no use-mpls=no use-upnp=no
                
                  0
                  Огромное спасибо за полезный скрипт!
                    0
                    После сбора статистика скажу, что сервера периодически уходят в даун. Чтобы нивелировать проблему добавил ротацию серверов из списка VPNBookServerAddresses. По-хорошему список серверов тоже можно парсить как и пароль, но мне лень это делать ;)
                    # VPNBookScript v2
                    :global VPNBookpIfName "pptp-out1"
                    :global VPNBookServerAddresses {"euro217.vpnbook.com";"euro214.vpnbook.com";"us1.vpnbook.com";"us2.vpnbook.com";"ca1.vpnbook.com";"de233.vpnbook.com"}
                    #:if ([:typeof $VPNBookServerAddresses] != "array") do={
                    #  :set VPNBookServerAddresses {"euro217.vpnbook.com";"euro214.vpnbook.com";"us1.vpnbook.com";"us2.vpnbook.com";"ca1.vpnbook.com";"de233.vpnbook.com"}
                    #}
                    
                    :global VPNBookErr false
                    :global VPNBookPassFile "VPNBookPass.txt"
                    :global VPNBookPass
                    :global VPNBookRun
                    
                    :global VPNBookServerIndex
                    :if ([:typeof $VPNBookServerIndex] != "num") do={:set VPNBookServerIndex 0}
                    
                    :if ([/interface pptp-client get $VPNBookpIfName running]) do={
                      :set VPNBookRun true
                    } else {
                      :if (!$VPNBookRun) do={
                        :set VPNBookServerIndex ($VPNBookServerIndex + 1)
                        :if ($VPNBookServerIndex>=[:len $VPNBookServerAddresses]) do={:set VPNBookServerIndex 0}
                      } else {
                        :set VPNBookRun false
                      }
                      :if (![/interface pptp-client get $VPNBookpIfName disabled]) do={/interface pptp-client set $VPNBookpIfName disabled=yes}
                      :do {/tool fetch url="http://парсер.хост/vpnbookpass.php" dst-path=$VPNBookPassFile} on-error={:set VPNBookErr true}
                      :delay 2
                      :do {:set VPNBookPass [/file get $VPNBookPassFile contents]} on-error={:set VPNBookErr true}
                      :if (!$VPNBookErr) do={
                        :if ([/interface pptp-client get $VPNBookpIfName password] != $VPNBookPass) do={/interface pptp-client set $VPNBookpIfName password=$VPNBookPass}
                        /interface pptp-client set $VPNBookpIfName connect-to=($VPNBookServerAddresses->$VPNBookServerIndex)
                        :log info ("VPNBook: Attempt to connect to: ".($VPNBookServerAddresses->$VPNBookServerIndex).". Password: $VPNBookPass")
                        /interface pptp-client set $VPNBookpIfName disabled=no
                      }
                    }
                    
                    

                    Переменная VPNBookRun нужна, чтобы после первого разрыва связи сохранять текущий адрес сервера, т.к. разрыв мог случится из-зи смены пароля. Поэтому чтобы не ротировать лишний раз «проверенный» сервер его индекс сохраняется на одну попытку повторного парсинга-подключения, а в дальнейшем, если сервер не отвечает, происходит ротация.
                      0
                      Если жалко лишней ненужной записи в флеш, можно заменить строку
                      /interface pptp-client set $VPNBookpIfName connect-to=($VPNBookServerAddresses->$VPNBookServerIndex)
                      
                      на
                      :if ([/interface pptp-client get $VPNBookpIfName connect-to] != $VPNBookServerAddresses->$VPNBookServerIndex) do={/interface pptp-client set $VPNBookpIfName connect-to=($VPNBookServerAddresses->$VPNBookServerIndex)}
                      
                  +1
                  vpnbook перешел на https, поэтому в парсере нужно поправить url
                    0
                    Ну что, господа, заменил vpnbook текстовой пароль картинкой.

                    Only users with full accounts can post comments. Log in, please.