Killswitch для Openvpn в Linux. Как сделать так, чтобы трафик не пошел в обход VPN

Преамбула

Итак, что такое killswitch. В случае использования VPN, это механизм, при котором, в случае «падения» VPN вы не спалитесь. Без killswitch обычно бывает так: сидите вы, работаете через VPN и считаете себя защищенным, хотя бы от подглядывания за вами провайдера (и сидящего за СОРМ’ом тов. майора), и тут фигак, VPN падает, ОС предоставляет вам доступ по умолчанию, и мессенджеры, открытые вкладки браузера, и вообще все-все-все выходят в Интернет через ваш обычный провайдерский IP.

Значит, надо сделать так, чтобы трафик, в случае отключения VPN никуда не ушел. Это и есть killswitch.

Первый опыт. Самый простой killswitch.

Изначально все было сделано очень просто. Дома стоял отдельный линуксовый «сервер», который предоставлял остальным устройствам доступ к Интернету, к домашним файл-помойкам (FTP и Samba) и PXE, на случай чего-нибудь переустановить. Внешний VPN, т.е. тот, который крутится на «сервере» — просто OpenVPN-клиент, который коннектится к VPN-провайдеру. И первый killswitch был очень простой: надо отрубить доступ всем клиентам из локальной сети.

Openvpn может при соединении или разъединении с VPN выполнять пользовательские скрипты, и в этих скриптах прописывалась команда iptables -P FORWARD DROP, если соединение падало, или iptables -P FORWARD ACCEPT, когда соединение устанавливалось.

Но такой подход несколько кривоват, подходит это хорошо только для FORWARD-трафика, а для локальной машины на Linux, т.е ноута, который постоянно таскаю на работу, фигово — сделать DROP по INPUT и OUTPUT-цепочкам, или вообще удалить дефолтный маршрут, так до поднятия VPN придется все это сначала «вернуть в зад» (не забыв перед этим закрыть браузер и мессенджеры).

Подробнее про первый способ можно прочесть тут (копия)

Простой Killswitch для локальной машины

1. Надо проверить конфигурацию ядра (см. Посмотреть опции компиляции ядра/узнать конфигурацию ядра Linux (копия), точнее, нас интересует опция CONFIG_NETFILTER_XT_MATCH_OWNER. Если она установлена в Yes (CONFIG_NETFILTER_XT_MATCH_OWNER=y), тогда можно переходить к следующему шагу, если она установлена в CONFIG_NETFILTER_XT_MATCH_OWNER=m, т.е. собрана в виде модуля (как у меня) — смело добавляем в автозагрузку команду (и перезагружаемся):

modprobe xt_owner

В некоторых ОС modprobe owner_xt, посмотрите сами, если modprobe с одним модулем не выдаст ошибку, значит модуль тот, который надо. Если выдаст — попробуйте другой вариант.
Если ядро скомпилировано с опцией CONFIG_NETFILTER_XT_MATCH_OWNER=n, тогда печально — придется пересобирать ядро.

2. Понадобится отдельная группа для запуска OpenVPN и других программ в обход VPN. Все остальное, естественно, должно резаться, если OpenVPN не запущен.
Создаем группу:

groupadd -r killswitch

или

groupadd --system killswitch

Естественно, имя группы killswitch можно заменить на свое. Нужна обязательно системная группа, иначе работать не будет. Про группы Linux можно почитать в источниках [2].

3. Выполняем команды IPTABLES:

iptables -A OUTPUT -m owner --gid-owner killswitch -j ACCEPT
iptables -A OUTPUT -o tun0 -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -j REJECT --reject-with icmp-admin-prohibited

Вместо tun0 вписываем имя устройства, которое будет создано OpenVPN Параметр можно узнать из конфига для соединения (dev <имя устройства>, например dev tun0). В конфиге можно его и поменять.

Что вообще делают эти команды:

1. Пакеты, отправленные процессами с GID killswitch, пропускаются в сеть.
2. Пакеты на интерфейсе tun0 пропускаются безусловно. Это тот самый сетевой интерфейс, который реализован поверх VPN-подключения. Если у вас этот сетевой интерфейс называется по-другому (опция dev в конфиге OpenVPN позволяет дать ему фиксированное имя вместо tunN), поменяйте его в правилах iptables выше.
3. Пакеты на интерфейсе lo точно так же пропускаются. lo — это loopback-интерфейс, на котором располагается известный 127.0.0.1 (localhost). Поскольку некоторые приложения используют localhost для коммуникации между процессами, его блокировать нежелательно.
4. Все остальные пакеты блокируются. Блокировка при этом происходит с отправкой ICMP-пакета «administratively prohibited» (код ошибки не играет существенной роли). Это лучше, чем просто дропать пакеты, так как в таком случае программы будут сразу получать ошибку, а не висеть до таймаута.
[1]

В источнике есть еще и дополнительные плюшки, как сделать это через CGROUPS

4. Осталось запустить OpenVPN от нужной группы:

sg openvpn --config /path/to/config/config.ovpn

sg, это команда наподобие sudo, только она позволяет запускать программы в нужной группе [4]

Проблема с доступом к сервисам в локальной сети.

Вышеприведенный способ режет совсем всё, т.е. доступ в локальную сеть тоже будет закрыт. А мне доступ в локальную сеть нужен, т.к. в ЛВС на работе присутствуют сервера, к которым нужен доступ. Я попытался добавить команды IPTABLES (да, о том, что порядок команд важен, я знаю) для доступа в локальную сеть, закрыв, при этом, доступ к локальному DNS-серверу и шлюзу (он же роутер с IP-адресом 192.168.0.1)

iptables -A OUTPUT -m owner --gid-owner killswitch -j ACCEPT
iptables -A OUTPUT -o tun0 -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -s 192.168.0.1 -j DROP
iptables -A OUTPUT -d 192.168.0.1 -j DROP
iptables -A INPUT -s 192.168.0.1 -j DROP
iptables -A INPUT -d 192.168.0.1 -j DROP
iptables -A OUTPUT -s 192.168.0.0/24 -j ACCEPT
iptables -A OUTPUT -d 192.168.0.0/24 -j ACCEPT
iptables -A OUTPUT -j REJECT --reject-with icmp-admin-prohibited

-s — входящий трафик
-d — исходящий

Но почему-то пакеты один хрен, уходили в сеть. Поясните, кто больше меня шарит в IPTABLES, где я накосячил.

В результате, пришел к Соломонову решению — открыть доступ не ко всей ЛВС, а только к нужным мне серверам.

Да, если еще один появится, придется отдельно разрешать доступ, что неудобно. Кто знает, как решить — подскажите.

Так что окончательная конфигурация такая:

iptables -A OUTPUT -m owner --gid-owner killswitch -j ACCEPT
iptables -A OUTPUT -o tun0 -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -s 192.168.0.66 -j ACCEPT
iptables -A OUTPUT -d 192.168.0.66 -j ACCEPT
iptables -A OUTPUT -s 192.168.0.68 -j ACCEPT
iptables -A OUTPUT -d 192.168.0.68 -j ACCEPT
iptables -A OUTPUT -j REJECT --reject-with icmp-admin-prohibited

Источники

1. Kill switch для OpenVPN на основе iptables (копия в PDF)
2. Как создать группы в Linux (команда groupadd)
3. Как заблокировать ip в iptables
4. sg

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *