openwrt скрипт перезапуска firewall после запуска
Точечный обход блокировок PKH на роутере с OpenWrt с помощью WireGuard и DNSCrypt
Чем отличается от подобных материалов?
Видеоверсия
Почему OpenWrt и WireGuard?
OpenWrt ставится на очень много моделей soho роутеров, конфигурируется и расширяется как душа пожелает. Сейчас многие прошивки роутеров — это надстройки над OpenWrt.
Wireguard используется из-за его быстрой и простой настройки, а так же из-за высокой скорости передачи через туннель.
Немного о WireGuard
В нашем случае сервер — это VPS вне РКН, клиент — OpenWrt роутер дома. Когда вы захотите зайти на pornolab telegram, ваш роутер направит трафик через сервер с WireGuard.
WireGuard поднимает site-to-site соединение, т.е. и у сервера и у клиента имеется серверная и клиентская часть конфигурации. Если не понятно — станет понятно когда увидите конфигурацию.
У сервера и у клиента есть свои собственные приватный и публичный ключи.
Настройка WireGuard на сервере
Я проделываю всё на Ubuntu 18.04, но в официальной документации есть инструкции по установке для всех известных и не очень ОС.
Установка
Установите software-properties-common — пакет предоставляет возможность добавления и удаления PPA
Генерируем ключи для сервера. Ключи сохраним в директории WireGuard для удобства
Соответственно в файле privatekey-server будет приватный ключ, а в publickey-server — публичный.
Так же сгенерируем сразу ключ для клиента:
Конфигурация
Конфиг хранится в /etc/wireguard/wg0.conf. Серверная часть выглядит так:
Address — адрес для интерфейса wg (адрес внутри туннеля)
PrivateKey — Приватный ключ (privatekey-server)
ListenPort — Порт на котором служба ожидает подключения
Ну и делаем маскарадинг, потому что мы будем использовать этот сервер для выхода в интернет
Обратите внимание, что имя интерфейса в вашем случае может отличаться:
PublicKey — публичный ключ нашего роутера (publickey-client)
AllowedIPs — подсети, которые будут доступны через этот туннель. Серверу требуется доступ только до адреса клиента.
Обе части хранятся в одном конфиге.
Включаем автозапуск при перезагрузке:
Делаем сервер маршрутизатором:
Настроим фаервол. Предположим, что у нас на сервере только WireGuard и ssh:
Сохраним конфигурацию iptables:
Поднимаем wg интерфейс первый раз вручную:
WireGuard сервер готов.
UPD 27.06.19 Если ваш провайдер до сих пор использует PPoE, то нужно добавить правило. Спасибо denix123
Настройка роутера
Я использую OpenWrt версии 18.06.1 на Xiaomi mi 3G и Asus RT-N16.
Логика работы роутера
Загружаем списки, помещаем их в iptables, все адреса из этих списков iptables помечает маркером 0x1. Далее все пакеты помеченные 0x1 идут в отдельную таблицу маршрутизации, все пакеты попавшие в эту таблицу маршрутизации идут через wg интерфейс.
Установка пакетов
Насчет занимаемого места на флеше, на всё понадобится примерно 0.9МБ. Если у вас совсем плохо с местом, замените curl wget’ом и можете не ставить dnscrypt-proxy.
Ставим пакеты. В OpenWrt это просто сделать через менеджер пакетов opkg:
Загрузка списков
Всё, что можно сделать через стандартные возможности OpenWrt, сделано через них. Всё остальное (кроме hotplug) я поместил в небольшой скрипт:
Списки запрещенных подсетей и адресов получаем файлами. Для них создаём директорию в /tmp. В /tmp — потому что это RAM, такая особенность OpenWrt, довольно удобная. На ROM роутера что-то писать лишний раз не стоит.
Выкачиваем списки с antifilter.download curl’ом, флаг z означает, что curl будет скачивать файл, только если удаленный файл отличается от локального или если его нет, как например в случае при загрузке роутера.
subnet.lst — список заблокированных подсетей, изменяется не часто.
ipsum.lst — список заблокированных адресов, который суммаризирован по маске. Вместо 150 тысяч записей получаем 15 тысяч — удобно.
После того как файлы у нас — рестартуем firewall, это нужно для того что бы ipset отработал и добавил списки в iptables, ipset у нас будет сконфигурен в /etc/config/firewall.
Скрипт этот мы добавляем в /etc/init.d/ назовём hirkn. Сделаем его исполняемым
Теперь у нас не просто скрипт, а целая служба. Для того, что бы он запускался при загрузке, делаем симлинк в /etc/rc.d. Нам нужно, что бы он запускался после всех остальных служб, поэтому делаем приставку S99
Списки нужно обновлять время от времени, добавляем запись в cron:
Мне кажется вполне достаточным обновлять их раз в сутки. Имейте в виду, что при добавлении списков в ipset, отваливается сеть, в моём случае это 2 секунды.
UPD: Если не хотите разрывов, то sigo73 и Grayver подсказали в комментариях как это осуществить.
Так же включите крон, по дефолту он отключен:
Конфигурация таблицы маршрутизации
Создаем таблицу маршрутизации для трафика через туннель, просто добавив строку:
в файл /etc/iproute2/rt_tables.
Создать дефолтный маршрут для таблицы «vpn» через wg интерфейс можно командой:
Но при рестарте сети маршрут пропадёт, поэтому создаём файл 30-rknroute в директории /etc/hotplug.d/iface/ с простым содержимым:
Это означает, что при включении\выключении интерфейсов будет добавляться наш маршрут. И соответственно, этот маршрут будет всегда прописан.
Конфигурация сети
Нам необходимо сконфигурировать WireGuard и правило для пакетов с меткой 0x1.
Конфигурация WireGuard располагается в /etc/config/network
private_key — это privatekey-client, который мы генерировали при настройке сервера
list addresses — адрес wg интерфейса
listen_port — порт на котором WireGuard принимает соединения. Но соединение будет происходить через порт на сервере, поэтому здесь мы не будем открывать для него порт на firewall
proto — указываем протокол, что бы openwrt понимало что это конфигурация WireGuard
public_key — ключ publickey-server
allowed_ips — подсети, в которые может ходить трафик через тунель, в нашем случае никаких ограничей не требуется, поэтому 0.0.0.0/0
route_allowed_ips — флаг, который делает роут через wg интерфейс для перечисленных сетей из параметра allowed_ips. В нашем случае это не нужно, эту работу выполняет iptables
endpoint_host — ip/url нашего wg сервера
persistent_keepalive — интервал времени, через который отправляются пакеты для поддержки соединения
endpoint_port — порт wireguard на сервере
Ещё в конфигурацию network добавим правило, которое будет отправлять весь трафик, помеченный 0x1, в таблицу маршрутизации «vpn»:
Конфигурация firewall
Добавим два правила маркировки пакетов, они не вписываются в синтаксис UCI openwrt, поэтому добавляем их «как есть» в /etc/firewall.user.
UPD: Grayver подсказал, что вполне себе вписываются. Зададим их после настройки ipset
Конфигурация фаервола находится в /etc/config/firewall
Добавляем зону для wireguard. В openwrt зоны — это кастомные цепочки в iptables. Таким образом создаётся зона с одним\несколькими интерфейсами и уже на неё вешаются правила. Зона для wg выглядит например вот так:
Мы разрешаем только выход трафика из интерфейса и включаем маскарадинг.
Теперь нужно разрешить переадресацию с lan зоны на wg зону:
Ну и последнее — это формирование списков в iptables с помощью ipset:
loadfile — файл из которого берем список
name — имя для нашего списка
storage, match — здесь указываем как хранить и какой тип данных. Будем хранить тип «подсеть»
UPD: Если хотите использовать список отдельных IP адресов, то вам необходимо увеличить размер списка ipset. В config ipset добавьте
Иначе вы будете получать ошибку
UPD: Добавим два правила маркировки пакетов
Эти правила подразумевают под собой, что все пакеты идущие в подсети из списков vpn_subnets и vpn_ipsum необходимо помечать маркером 0x1.
После этого рестартуем сеть:
и запускаем скрипт:
После отработки скрипта у вас должно всё заработать. Проверьте маршрут на клиенте роутера:
Бонусом настроим DNSCrypt
Зачем? Ваш провайдер может заботливо подменять ip-адрес заблокированного ресурса, таким образом перенаправляя вас на свой ip с заглушкой, ну и наш обход по ip в данном случае не поможет. Для подмены не всегда даже нужно использовать dns сервер провайдера, ваши запросы могут перехватываться и ответы подменяться. Ну и к слову, это может делать не только провайдер.
Настраиваем конфиг /etc/config/dnscrypt-proxy примерно так:
Таким образом у нас есть сервис dnscrypt на порту 5353 доступный на localhost.
Resolver — это dns, сервер поддерживающий шифрование. На роутере в файле /usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv содержится список доступных, на момент выпуска установленной версии dnscrypt, серверов. А вот здесь https://dnscrypt.info/public-servers/ вообще все доступные серверы dnscrypt. Можете выбрать другого резолвера и/или добавить серверов для отказоустойчивости. Имейте в виду, что бы DNSCrypt работал с выбраным резолвером, он должен быть указан в dnscrypt-resolvers.csv.
Настраиваем dnsmasq на работу с dnscrypt. В /etc/config/dhcp комментируем строчку:
для того что бы не были задействованы dns серверы провайдера.
Запись list server ‘domain/ip_dns’ указывает какой dns сервер использовать для резолва указанного домена. Таким образом мы не задействуем dnscrypt для синхронизации ntp — для работы службе dnscrypt важно иметь актуальное время.
При загрузке роутера, скрипт hirkn запускается быстрее чем стартует dnscrypt, таким образом домен antifilter.download не резолвится и списки не скачиваются. Можно сделать задержку или ещё что придумать, но пока что не вижу смысла.
UPD: необходимо добавить строку
В итоге мы получаем такую вставку в конфиг:
UPD: На некоторых устройствах DNSCrypt запускается всё-равно после скрипта. Самый простой способ исправить это — добавить в /etc/config/dhcp строку
Отключаем использование провайдерских DNS для интерфейса wan
В /etc/config/network добавляем строку
к интерфейсу wan.
Получаем такую конфигурацию
Добавляем в автозагрузку и стартуем dnscrypt:
Илюстрация работы без DNSCrypt и c DNSCrypt
Автоматически развертываем с помощью Ansible
Playbook и темплейты лежат на github. Используется модуль, в нём не нужен python на роутере и есть поддержка uci. Я постарался сделать так, что бы ваша конфигурация OpenWrt осталась не тронутой, но всё равно будьте бдительны.
Устанавливаем модуль gekmihesg/ansible-openwrt:
Копируем плейбук и темлпейты:
Добавляйте ваш роутер в hosts:
Подставляете свои переменные в hirkn.yml:
Обязательно нужно задать:
wg_server_address — ip/url wireguard сервера
wg_private_key, wg_public_key — приватный ключ клиента и публичный сервера
Остальное можно не менять или менять, в зависимости от того как настроен WireGuard сервер
После выполнения плейбука, роутер сразу начнёт выполнять обход блокировок через ваш wireguard сервер.
Почему не BGP?
Под openwrt есть две утилиты реализующих BGP — quagga и bird. Quagg’у мне не удалось заставить забирать данные с antifilter. Bird подружился с сервисом с полпинка, но как заставить добавлять полученным подсетям интерфейс по умолчанию я, к сожалению, не понял. (Буду рад узнать как это можно реализовать).
В комментариях к подобным статьям я видел, что роутеры у людей «призадумывались» на некоторое время, когда те загоняют списки в таблицу маршрутизации. С реализацией через ipset мой Xiaomi mi 3G задумывается на 2 секунды (Asus rt-n16 на 5 секунд), когда скармливаешь ему список из 15ти тысяч подсетей. При дальнейшей работе нагрузки на процессор не замечал.
Все материалы не являются призывом к действию и представлены для ознакомления с функционалом ОС Linux.
Описание работы файрвола в OpenWrt
Файрвол UCI объединяет один и более интерфейсов в специальные зоны, которые используются для для описания правил по-умолчанию для данного интерфейса, правил пересылки пакетов между интерфейсами, а также дополнительные правила, которые не подпадают под первые два типа. В конфигурационном файле правила по-умолчанию идут первыми, но вступают в силу последними. Система netfilter является системой фильтрации с последовательной обработкой, в которой пакеты последовательно, по цепочке, обрабатываются различными правилами. Первое совпавшее правило выполняется, но оно часто выполняет переход на другую цепочку правил, по которой движется пакет пока не встретит команды ACCEPT или DROP/REJECT. Правила с такими командами выполняются последними в цепочке правил, поэтому правила по-умолчанию вступят в силу последними, а более конкретные правила будут проверяться в первую очередь.
Ключевые понятия файрвола iptables
iptables — это утилита для настройки межсетевого экрана linux, которая предустанавливается по умолчанию во все сборки Linux, начиная с версии 2.4. Есть она и в OpenWrt. Как и все файрволлы, iptables оперирует некими правилами (rules), на основании которых решается судьба пакета, который поступил на интерфейс сетевого устройства (роутера). Каждое правило в iptables состоит из критерия (условие, под которое должны подпадать параметры пакета или текущее соединение, чтобы сработало действие), действия (операция, которую нужно проделать с пакетом или соединением) и счётчика (считает сколько пакетов было подвержено действию правила).
В базовых цепочках обязательно устанавливается политика по умолчанию, как правило – принимать (ACCEPT) или сбрасывать (DROP) пакеты. Действует она только в цепочках INPUT, FORWARD и OUTPUT.
Таблицы — это набор базовых и пользовательских цепочек. В зависимости от того, в какой таблице находится цепочка правил, с пакетом или соединением производятся определённые действия. Существует 5 таблиц, основные из которых:
Этот рисунок дает довольно ясное представление о порядке прохождения пакетов через различные цепочки. В первой точке принятия решения о маршрутизации (routing decision) все пакеты, предназначенные данному хосту направляются в цепочку INPUT, остальные – в цепочку FORWARD.
Обратите внимание также на тот факт, что пакеты, с адресом назначения на брандмауэр, могут претерпеть трансляцию сетевого адреса (DNAT) в цепочке PREROUTING таблицы nat и соответственно дальнейшая маршрутизация в первой точке будет выполняться в зависимости от произведенных изменений.
Наиболее используемые действия :
Помимо этих четырех, есть ещё масса других действий, которые называются расширенными (extension modules):
Есть действия, которые доступны только в определенной цепочке и таблицах, например, только в таблице nat и цепочках OUTPUT и PREROUTING доступно действие DNAT, которое используется в NAT’ировании и меняет Destination IP пакета. В той же таблице, только в цепочке POSTRUNNING доступно действие SNAT, меняющее Source IP пакета.
Отдельно остановимся на действии MASQUERADE, которое делает то же самое что SNAT, только применяется на выходном интерфейсе, когда IP адрес может меняться, например, когда назначается по DHCP.
Реализация iptables в OpenWrt
Для зоны также есть правила:
Цепочку FORWARD проходят ВСЕ пакеты, которые движутся через наш firewall/роутер. Не используйте цепочку INPUT для фильтрации транзитных пакетов, они туда просто не попадают! Через эту цепочку движутся только те пакеты, которые предназначены данному хосту.
Секция forwarding контролирует прохождение трафика между зонами и позволяет включить MSS clamping для отдельных адресов назначений (destination). В одном правиле forwarding можно указать только одно назначение. Чтобы разрешить трафик в обе стороны между зонами необходимо создать два forwardings с src и dest в каждом.
Именно поэтому в таблице Filter для зон присутствуют отдельные цепочки. Эти цепочки применяются при передачи трафика между зонами. Иначе говоря, обычный трафик от клиента в Интернет и обратно не попадает в эти цепочки, он виден только в базовой цепочке FORWARD, потому что хостом назначения не является ни интерфейс lan роутера, ни wan. При необходимости, цепочка FORWARD передает обработку в цепочки zone_lan_forward, zone_wan_forward, zone_uplink_forward.
Посмотрим на цепочки зон. Например, для lan имеются: Chain zone_lan_dest_ACCEPT, Chain zone_lan_forward, Chain zone_lan_input, Chain zone_lan_output, Chain zone_lan_src_ACCEPT. Такие же цепочки есть и для других зон, например, для wan. Как видно из скриншота, все, что попадает в цепочку по правилу input_lan_rule, пересылается в цепочку zone_lan_input, где принимается (ACCEPT). А маршрутизируемый трафик из цепочки zone_lan_forward передается в цепочки зон wan и uplink (это моя кастомная зона).
Зона zone_wan_dest — это те пакеты, которые адресованы непосредственно интерфейсу wan (10.54.192.1 в данном случае), а не в интернет.
Как трафик попадает в эти цепочки? Ну допустим, вы обращаетесь к роутеру самому или делаете трассировку трафика, когда на каждом хопе destination’ом у вас являются разные хосты. На скриншоте мы сначала попадаем в lan интерфейс (192.168.2.1) на первом хопе, а потом в wan (10.54.192.1) на втором:
Также в OpenWrt присутствуют и таблицы NAT с цепочками PREROUTING, POSTROUTING и цепочками пре- и построутинга между зонами. маскарадинг осуществляется непосредственно на цепочка построутинга зон.
Настройка файрвола OpenWrt
Firewall configuration /etc/config/firewall
OpenWrt’s firewall management application fw3 has three provisioning mechanisms
Most of the information in this wiki will focus on the configuration files and content. The LuCI and UCI interfaces are user abstractions, ultimately modifying the configuration files.
Management
Web interface instructions
LuCI is a good mechanism to view and modify the firewall configuration.
Make changes and reload using the Save & Apply button.
Command-line instructions
UCI is a low-level abstraction to the configuration files and can be accessed remotely through SSH.
These would be presumed to be the final rules (each proto creates a rule) in the VPN → LAN forward chain, as all packets from VPN will be rejected.
Show firewall configuration:
UCI is useful to view the firewall configuration, but not to do any meaningful modifications for the following reasons:
Config sections
Below is an overview of the section types that may be defined in the firewall configuration.
Defaults
The defaults section declares global firewall settings which do not belong to specific zones:
Options
Name | Type | Required | Default | Description |
---|---|---|---|---|
input | string | no | REJECT | Set policy for the INPUT chain of the filter table. |
forward | string | no | REJECT | Set policy for the FORWARD chain of the filter table. |
output | string | no | REJECT | Set policy for the OUTPUT chain of the filter table. |
drop_invalid | boolean | no | 0 | Drop invalid packets (e.g. not matching any active connection). |
syn_flood | boolean | no | 0 | Enable SYN flood protection (obsoleted by synflood_protect setting). |
synflood_protect | boolean | no | 0 | Enable SYN flood protection. |
synflood_rate | string | no | 25 | Set rate limit (packets/second) for SYN packets above which the traffic is considered a flood. |
synflood_burst | string | no | 50 | Set burst limit for SYN packets above which the traffic is considered a flood if it exceeds the allowed rate. |
tcp_syncookies | boolean | no | 1 | Enable the use of SYN cookies. |
tcp_ecn | boolean | no | 0 | Enable/Disable Explicit Congestion Notification. Implemented upstream in Linux Kernel. See ip-sysctl.txt. |
tcp_window_scaling | boolean | no | 1 | Enable TCP window scaling. |
accept_redirects | boolean | no | 0 | Accepts redirects. Implemented upstream in Linux Kernel. See ip-sysctl.txt. |
accept_source_route | boolean | no | 0 | Implemented upstream in Linux Kernel. See ip-sysctl.txt. |
custom_chains | boolean | no | 1 | Enable generation of custom rule chain hooks for user generated rules. User rules would be typically stored in firewall.user but some packages e.g. BCP38 also make use of these hooks. |
disable_ipv6 | boolean | no | 0 | Disable IPv6 firewall rules. |
flow_offloading | boolean | no | 0 | Enable software flow offloading for connections. (decrease cpu load / increase routing throughput) |
flow_offloading_hw | boolean | no | 0 | Enable hardware flow offloading for connections. (depends on flow_offloading and hw capability) |
tcp_reject_code | reject_code | no | 0 | Defined in firewall3/options.h. Seems to determine method of packet rejection; (tcp reset, or drop, vs ICMP Destination Unreachable, or closed) |
any_reject_code | reject_code | no | 1 | Defined in firewall3/options.h. Seems to determine method of packet rejection; (tcp reset, or drop, vs ICMP Destination Unreachable, or closed) |
auto_helper | bool | no | 1 | Enable Conntrack helpers |
Zones
A zone section groups one or more interfaces and serves as a source or destination for forwardings, rules and redirects.
Options
Forwardings
The forwarding sections control the traffic flow between zones, and may enable MSS clamping for specific directions.
Options
Rules
The rule section is used to define basic accept, drop, or reject rules to allow or restrict access to specific ports or hosts.
If neither src nor dest are given, the rule defaults to an outgoing traffic rule
Options
ICMP name types
address-mask-reply | host-redirect | pong | time-exceeded |
address-mask-request | host-unknown | port-unreachable | timestamp-reply |
any | host-unreachable | precedence-cutoff | timestamp-request |
communication-prohibited | ip-header-bad | protocol-unreachable | TOS-host-redirect |
destination-unreachable | network-prohibited | redirect | TOS-host-unreachable |
echo-reply | network-redirect | required-option-missing | TOS-network-redirect |
echo-request | network-unknown | router-advertisement | TOS-network-unreachable |
fragmentation-needed | network-unreachable | router-solicitation | ttl-exceeded |
host-precedence-violation | parameter-problem | source-quench | ttl-zero-during-reassembly |
host-prohibited | ping | source-route-failed | ttl-zero-during-transit |
Redirects
Port forwardings (DNAT) are defined by redirect sections. Port Redirects are also commonly known as “port forwarding” or “virtual servers”.
Destination NAT
Source NAT
Options
IP sets
fw3 supports referencing or creating IP sets to simplify matching of large address or port lists without the need for creating one rule per item to match.
Options
Storage / Match Options
The order of datatype matches is significant
Family | Storage | Match | Notes |
---|---|---|---|
ipv4 | bitmap | ip | Requires iprange option |
ipv4 | bitmap | ip mac | Requires iprange option |
ipv4 | bitmap | port | Requires portrange option |
any | hash | ip | — |
any | hash | net | — |
any | hash | ip port | — |
any | hash | net port | — |
any | hash | ip port ip | — |
any | hash | ip port net | — |
— | list | set | Meta type to create a set-of-sets |
Includes
It is possible to include custom firewall scripts by specifying one or more include sections in the firewall configuration:
Options
Includes of type script may contain arbitrary commands, for example advanced iptables rules or tc commands required for traffic shaping.
Example
Here is an example of /etc/firewall.user script that allows to CloudFlare.com to access HTTP 80 and HTTPS 443 ports. Use if your uhttpd is hidden behind CF proxy.
Self-registration in the wiki has been disabled.
If you want to contribute to the OpenWrt wiki, please post HERE in the forum or ask on IRC for access.
Except where otherwise noted, content on this wiki is licensed under the following license:
CC Attribution-Share Alike 4.0 International