Есть относительно неплохой бесплатный сервис VPN vpnbook.com, мы про него когда-то давно писали, а я одно время даже активно пользовался, пока меня не задолбали некоторые ограничения, и я не перешел на лучший и более надежный в плане безопасности Riseup, но в качестве резерва, почему бы не иметь и его? Заодно и знакомый попросил его настроить.
В общем, пошел я на сайт, а там все изменилось, появились и периодически добавляются новые сервера, старые подохли, в общем контора активно цветет и пахнет.
Так вот, на случай появления новых серверов, придется идти на сайт, скачивать конфиги, при необходимости добавлять свои параметры, и т.д. А зачем это каждый раз делать руками, если можно автоматизировать?
1. Вытащить с сайта список конфигов
2. Скачать архивы конфигов на локальный компьютер и распаковать их
3. Автоматически добавить в конфиг дополнительные параметры, например изменить уровень script-security
и добавить пользовательские скрипты, выполняющиеся при соединении и разрыве соединения с сервером, и т.д. Подробности тут или тут
4. Конфиги для каждого сервера поставляются в нескольких вариантах, для соединения по разным портам, например TCP 443, TCP 80, UDP 25000, UDP 53. Сервера различаются по странам. Соответственно, надо предусмотреть возможность выбора всех или определенных конфигов.
Нам понадобится какой-нибудь парсер HTML. Я использую xidel
, о котором недавно писал
1. Добавляем в начало скрипта необходимые переменные:
VPNBOOKPAGE="https://www.vpnbook.com/"
WORKDIR="/tmp/vpnbook/"
UNPDIR="/tmp/vpnbook/unpack/"
HTMLFILE="vpnhtml.html"
Страница, с которой будем выдирать ссылки на архивы, рабочий каталог скрипта, каталог, куда будем распаковывать архивы и имя файла, под которым сохраним HTML-страницу сайта с нужными данными.
2. Предусматриваем возможность удалить каталог с распакованными конфигами (если пользователь запустит скрипт с ключом -с
):
if [[ "$1" == "-c" ]]; then echo "Cleaning unpack directory..." rm -rf "$UNPDIR" fi
3. Удаляем ранее сохраненный HTML-файл (иначе новые wget
будет сохранять под именами vpnhtml.html.1
, vpnhtml.html.2
и т.д.) и создаем рабочий каталог и каталог для распаковки архивов. Путь будет создан со всеми подкаталогами, если он ранее не существовал. Если каталог уже существовал, то никакой ошибки не будет.
rm "$WORKDIR$HTMLFILE"
mkdir -p "$WORKDIR"
mkdir -p "$UNPDIR"
1. Сохраняем на диск главную страницу сайта:
echo "Get vpnbook page..."
wget -P $WORKDIR --default-page=$HTMLFILE --header="Content-type: text/html" $VPNBOOKPAGE
2. … и проверяем, загрузилась ли она:
if [[ ! -f "$WORKDIR$HTMLFILE" ]];then echo "Page not downloaded!" exit fi
3. Получаем ссылки на архивы с конфигами. Ссылка на архив выглядит как обычная HTML ссылка a href
внутри элемента <li>
.:
<li><strong><span class="red">Server:</span></strong> <a href="/free-openvpn-account/VPNBook.com-OpenVPN-PL226.zip">Download PL226 Server OpenVPN Certificate Bundle</a></li>
Вообще вытаскивать что-либо из HTML регулярками плохо и некультурно, поэтому воспользуемся парсером xidel
.
Вытаскиваем все ссылки, точнее, их атрибуты href
, и фильтруем необходимые (содержащие ZIP-архивы) с помощью grep
:
xidel -s --extract "//a/@href" "$WORKDIR$HTMLFILE" |grep ".zip"
4. Полученные данные обрабатываем в цикле:
4.1. Скачиваем архив
4.2. Распаковываем содержимое в $UNPDIR
.
4.3. Удаляем архив.
Цикл целиком:
for ZIPURL in $(xidel -s --extract "//a/@href" "$WORKDIR$HTMLFILE" |grep ".zip"); do ZIPNAME=`basename $ZIPURL` echo "Download $ZIPNAME..." wget -P $WORKDIR "$VPNBOOKPAGE/$ZIPURL" >/dev/null 2>/dev/null if [ -f "$WORKDIR$ZIPNAME" ];then echo "Unpacking $ZIPNAME..." unzip -o "$WORKDIR$ZIPNAME" -d "$UNPDIR" >/dev/null 2>/dev/null rm "$WORKDIR$ZIPNAME" fi done
5. Минус конфигурационных файлов Vpnbook — концы строк в файле .ovpn
CR+LF, т.е. формата Windows. Ищем все распакованные файлы (*.ovpn
) в директории из переменной $UNPDIR
, и заменяем в каждом файле концы строк Windows на концы строк Linux (LF). Делаем это в цикле sed
‘ом:
echo -n "Replacing Windows line ends" for FLE in $(find $UNPDIR -maxdepth 1 -iname "*.ovpn"); do echo -n "." sed -i 's/\r$//' "$FLE" done echo
Готово, конфиги получены.
Как я уже говорил, многие пользователи правят конфиги, добавляя необходимые им параметры, например, параметр daemon
, позволяющий запускаться Openvpn в фоновом режиме, или параметры script-security, up <scriptfile>, down <scriptfile>
, позволяющие Openvpn выполнять пользовательские скрипты при установке и разрыве соединения. Каждый раз при обновлении серверов неудобно редактировать/добавлять вручную эти параметры, особенно, если для любого сервера данного VPN они одинаковы. Будем автоматизировать.
Некоторые уточнения:
— если параметр (например auth-user-pass
) уже есть в конфиге, то его необходимо отредактировать
— если параметра в конфиге нет, добавить.
— добавлять новые параметры будем в начало конфигурационного файла, т.к. в конце у файлов конфигурации для vpnbook хранятся сертификаты в BASE64.
1. Для хранения пользовательских параметров заведем массив ADD_COMMANDS
и наполним его содержимым. Для примера я хочу запускать пользовательские скрипты при установке/разрыве соединения, а также автоматически вводить имя пользователя и пароль (все равно они для всех одинаковые, сервис без регистрации). Заведу в начале скрипта массив:
ADD_COMMANDS[0]="script-security 2"
ADD_COMMANDS[1]="up '~/openvpn/vpnbook/vb-routes up'"
ADD_COMMANDS[2]="down '~/openvpn/vpnbook/vb-routes down'"
ADD_COMMANDS[3]="auth-user-pass ~/openvpn/vpnbook/vpnbook.auth"
2. Для работы с параметрами заведем функцию add_commands()
, которая будет принимать единственный параметр — полный путь к редактируемому файлу.
3. В функции получим количество элементов массива в переменную $CTR
и заведем счетчик цикла:
CTR="${#ADD_COMMANDS[*]}"; I="0"
4. Организуем цикл:
until [ "$CTR" -eq "$I" ]; do [Тут будет код :)] done
5. В цикле:
5.1. Вытаскиваем в переменную $CMND_
пользовательскую команду из текущего элемента массива:
CMND_="${ADD_COMMANDS[I]}"
5.2. Вытаскиваем первое слово из команды (script-security
или auth-user-pass
, например). Его будем искать, и, соответственно, принимать решение, заменять существующую опцию в конфиге или добавлять новую:
CMND_ST=`echo "$CMND_" |awk '{print $1}'`
5.3. Считаем количество строк, содержащих эту опцию в конфиге, с помощью grep
:
CMND_C=`grep -c "$CMND_ST" "$1"`
5.4. Если таких строк нет, то добавляем, если уже есть — то редактируем:
if [ "$CMND_C" -eq 0 ];then #not found, add else #found, replace fi
5.4.1. Добавление строки:
sed -i -e "1 s%^%$CMND_\n%" "$1"
5.4.2. Замена строки, начинающейся с ключевого слова из переменной $CMND_ST
на пользовательскую опцию (в переменной $CMND_
):
sed -i "s%^ *$CMND_ST.*%$CMND_%" "$1"
5.5. Увеличиваем счетчик цикла на единицу:
let "I+=1"
Функция целиком:
add_commands() #$1-output file { CTR="${#ADD_COMMANDS[*]}"; I="0" until [ "$CTR" -eq "$I" ]; do CMND_="${ADD_COMMANDS[I]}" CMND_ST=`echo "$CMND_" |awk '{print $1}'` CMND_C=`grep -c "$CMND_ST" "$1"` if [ "$CMND_C" -eq 0 ];then #not found, add sed -i -e "1 s%^%$CMND_\n%" "$1" else #found, replace sed -i "s%^ *$CMND_ST.*%$CMND_%" "$1" fi let "I+=1" done }
В самом скрипте добавляем цикл обработки скачанных и распакованных конфигов, также выбирая их командой find
:
echo -n "Add commands" for FLE in $(find $UNPDIR -maxdepth 1 -iname "*.ovpn"); do echo -n "." add_commands "$FLE" done echo
Так, а теперь пользователю нужно отобрать определенные конфиги. Имя файла у vpnbook стандартизировано и имеет такой вид:
vpnbook-странаNсервера-порт.ovpn
, например, vpnbook-ca198-tcp80.ovpn
.
Т.е. выбор нужных файлов легко произвести по маске.
1. Заведем переменные для хранения выходной директории и маски файлов. Например, выберем конфиги для 80-го порта:
OUTDIR="~/openvpn/vpnbook/"
OUTMASK="*tcp80.ovpn"
2. Проверяем не пуста ли переменная $OUTDIR
, далее с помощью find
выбираем нужные файлы по маске, и в цикле for
копируем их в нужный каталог:
#copyng to outdir if [ -n "$OUTDIR" ]; then echo "Copy to outdir:" for FLE in $(find $UNPDIR -maxdepth 1 -iname $OUTMASK); do if [ -n "$FLE" ]; then BN=`basename $FLE` echo "$BN" cp "$FLE" "$OUTDIR$BN" fi done fi