OpenVPN-клиент умеет получать маршруты от OpenVPN-сервера. На Linux-машинах клиент по умолчанию добавляет полученные маршруты в таблицу "main", что не всегда удобно. Кроме того может возникнуть необходимость отклонить часть маршрутов. О возможных способах решениях этих задач и пойдёт речь далее.
В конфигурацию OpenVPN-клиента можно добавить опцию "route-noexec", которая запрещает автоматическое добавление маршрутов, и позволяет с помощью параметра "route-up" указать скрипт, которому будут переданы маршруты, и который сможет их обработать.
В итоге в конфигурацию клиента надо добавить примерно такие строки:
route-noexec route-up "/etc/openvpn/routes.sh"
И далее остаётся только написать сам скрипт. Перед написанием скрипта следует знать что все необходимые параметры передаются через параметры окружения. Основные параметры окружения:
- dev: имя интерфейса, пример: "tun_work";
- dev_type: тип интерфейса, пример: "tun";
- route_net_gateway: шлюз по умолчанию на стороне клиента, пример: "1.1.1.1";
- route_vpn_gateway: шлюз внутри VPN-сети, пример: "10.14.0.1";
- route_network_X: сеть номер X, пример: "172.16.1.0";
- route_netmask_X: маска сети номер X, пример: "255.255.255.0";
- route_gateway_X: маршрут для сети номер X, пример: "10.14.0.1";
Количество переданных маршрутов заранее неизвестно и надо последовательно перебирать маршруты начиная с X=1 до тех пор, пока соответствующие переменные окружения не окажутся пустыми.
Скрипт на bash, добавляющий маршруты в таблицу net_main_clients будет выглядеть так:
#!/bin/bash # Settings RTTABLE="net_main_clients" IPROUTE="/sbin/ip" # Variable examples # # dev=tun_work # dev_type=tun # route_net_gateway=1.1.1.1 # route_vpn_gateway=10.14.0.1 # route_gateway_1=10.14.0.1 # route_network_1=172.16.0.1 # route_netmask_1=255.255.255.0 echo "Process routes..." ROUTENUM=1 while true; do R_NETWORK=`eval "echo \\$route_network_${ROUTENUM}"` R_NETMASK=`eval "echo \\$route_netmask_${ROUTENUM}"` R_GATEWAY=`eval "echo \\$route_gateway_${ROUTENUM}"` ROUTENUM=$((ROUTENUM+1)) if [ "${R_NETWORK}" = "" ]; then break; fi ROUTECMD="${IPROUTE} route add ${R_NETWORK}/${R_NETMASK} via ${R_GATEWAY} table ${RTTABLE}" echo ${ROUTECMD} ${ROUTECMD} done
К сожалению скрипт состоит почти исключительно из bash-специфичных конструкций. Написать подобный скрипт на POSIX Shell вряд ли получится, но в качестве альтернативы для тех, кто не очень любит bash, приведём листинг полностью аналогичного скрипта на fish:
#!/usr/bin/fish # Settings set RTTABLE "net_localnet" set IPROUTE "/sbin/ip" # Variable examples # # dev=tun_work # dev_type=tun # route_net_gateway=1.1.1.1 # route_vpn_gateway=10.14.0.1 # route_gateway_1=10.14.0.1 # route_network_1=172.16.0.1 # route_netmask_1=255.255.255.0 echo "Process routes..." set ROUTENUM 1 while true eval "set R_NETWORK \$route_network_$ROUTENUM" eval "set R_NETMASK \$route_netmask_$ROUTENUM" eval "set R_GATEWAY \$route_gateway_$ROUTENUM" set ROUTENUM (math $ROUTENUM+1 ) if test "$R_NETWORK" = "" break; end set ROUTECMD "$IPROUTE route add $R_NETWORK/$R_NETMASK via $R_GATEWAY table $RTTABLE" echo $ROUTECMD eval $ROUTECMD end
Допустим мы хотим отклонять маршруты для сетей, начинающихся на 192.168. для этого в bash-скрипт перед добавлением маршрута надо добавить примерно такую проверку:
if [[ "${R_NETWORK}" =~ ^192\.168\. ]]; then continue; fi
В случае скрипта на fish код условия, вставляемый перед добавлением маршрута будет немного отличаться:
if string match -rai "^192\.168\." "$R_NETWORK" continue; end
Возможны и более сложные сценарии использования скриптов-обработчиков маршрутов OpenVPN, здесь показана только общая идея. Ну и для более сложных вариантов лучше использовать полноценные языки программирования. На этом всё. Приятной работы!