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, здесь показана только общая идея. Ну и для более сложных вариантов лучше использовать полноценные языки программирования. На этом всё. Приятной работы!
