Почти 4 года назад я опубликовал статью-мануал о том, как на роутере с OpenWrt сделать обход блокировок РКН. Всё это время мне много писали с просьбой помочь: не у всех всё заводилось с первого раза. Поэтому я решил написать материал, как самостоятельно искать, в чём именно проблема на роутере. В этой части разберёмся, что именно не работает, и как это исправить.


Первая часть. Установка и настройка


Написав тот материал, я рассчитывал что им будут пользоваться люди, связанные с ИТ. Но материал так разлетелся, что я до сих пор встречаю упоминания на форумах и в блогах. Если вы не привыкли страдать, то, возможно, это не для вас. Надо понимать, что у вас может ничего не заработать с полпинка.


Так же я рекомендую в идеале купить для этих целей отдельный роутер. Если у вас будет отдельный роутер для этого, в случае неудачи, вы вернёте старый роутер на место, и всё будет ок. Более бюджетный вариант — это поставить OpenWrt на вируталку и там попробовать всё настроить.


У многих возникают проблемы из-за неподдерживаемых роутеров:


  • Если ваш роутер официально не поддерживается OpenWrt, вполне вероятно, что у вас возникнут проблемы (про это есть в конце).
  • Если у вас стоит выбор, какое устройство купить, то не покупайте устройства, которые официально не поддерживаются сообществом OpenWrt. Сейчас можно купить недорогой роутер, на который можно поставить стабильную версию. Лучше брать роутер как минимум с 128МБ ROM и 256MB RAM. Нормальные объёмы чипов и стабильная версия очень облегчают жизнь.

Если у вас не работает роутер со свежеустановленной OpenWrt и нет доступа к интернету, то сначала разберитесь с этим и только потом приступайте к обходу блокировок.


Итак, вы всё сделали по инструкции или с помощью ansible, но обход блокировок не работает. Давайте разбираться.


Видеоверсия



Как понять, что трафик к заблокированным ресурсам идёт через туннель на роутере


Ну самое очевидное — это открыть сайт какого-нибудь заблокированного ресурса конечно.
Чтобы точно убедиться, что трафик перенаправляет в туннель именно роутер, а не ваш vpn на устройстве или какое-нибудь расширение браузера, используйте утилиты traceroute


Для Linux и MacOS это traceroute\mtr


mtr zona.media

Для windows tracert


tracert zona.media

Эти утилиты показывают маршрут пакета, который идёт к указанному заблокированному хосту.
Например, ваш wg сервер имеет адрес 10.7.0.1. Может быть несколько сценариев:


  1. Первой строкой идёт адрес вашего роутера, например 192.168.1.1 (или имя OpenWrt.lan), и второй строчкой ваш wg шлюз, и дальше доходит до конечного ip адреса, в который резолвится этот домен

Это значит, что пакет идёт через туннель на роутере, и всё хорошо. Можно ещё посмотреть, что дальше идут имена шлюзов содержащих название ДЦ, где вы купили виртуалку.


  1. Если первой же строкой у вас идёт не ваш роутер, а, например, адрес вашего wg сервера, то значит, что трафик в туннель сразу заворачивается на устройстве. Скорее всего, у вас включен vpn.


  2. Первой строкой идёт ваш роутер, потом шлюз провайдера и потом либо ничего, либо перенаправление на какой-то местный сервер. Это значит, что трафик не перенаправляется в туннель на роутере, а идёт по маршруту, который придумал ваш провайдер.



Как выключить обход блокировок


Это может потребоваться для troubleshooting'a, в том числе. Проще всего выключить маршрутизацию.


Два варианта: один временный — до первого рестарта сети, второй постоянный.


Временный и быстрый


Удаляем маршрут


ip route del table vpn default dev wg0

Чтоб включить обратно, либо


ip route add table vpn default dev wg0

либо


/etc/init.d/network restart

Постоянный


Идём в файл /etc/hotplug.d/iface/30-rknroute и комментируем единственную строку


#ip route add table vpn default dev wg0

рестартуем сеть


/etc/init.d/network restart

Всё, теперь таблица маршрутизации vpn не отправляет часть трафика на wg интерфейс, а он весь идёт через дефолтный шлюз.


Но помните, что трафик заблокированных ресурсов всё также маркируется, и всё остальное никуда не девается.


Проблемы с DNS. У вас не открываются любые сайты, но проходит пинг до ip адресов


~$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=111 time=51.8 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=111 time=178 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=111 time=51.7 ms
^C
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 51.680/93.695/177.655/59.368 ms

Скорее всего, проблема с DNS. В моей инструкции сломать доступ в интернет может только DNSCrypt.
На роутере проверяем резолвится ли домен, для примера я возьму свой домен


nslookup itdog.info

Если домен резолвится, мы получаем такой ответ:


root@OpenWrt:~# nslookup itdog.info
Server:     127.0.0.1
Address:    127.0.0.1:53

Non-authoritative answer:
Name:   itdog.info
Address: 95.217.5.75

Это означает, что с DNS на роутере у вас всё ок.


Если ответ nslookup выглядит следующим образом


root@OpenWrt:~# nslookup itdog.info 127.0.0.1
;; connection timed out; no servers could be reached

А запросы к сторонним DNS серверам выполняются


root@OpenWrt:~# nslookup itdog.info 8.8.8.8
Server:     8.8.8.8
Address:    8.8.8.8:53

Non-authoritative answer:

Non-authoritative answer:
Name:   itdog.info
Address: 95.217.5.75

Это значит, что у вас не работает локальный (на роутере) DNS сервер.


Дело, скорее всего, в DNSCrypt. Убедимся в этом, он висит на 127.0.0.53


root@OpenWrt:~# nslookup itdog.info 127.0.0.53
nslookup: write to '127.0.0.53': Connection refused
;; connection timed out; no servers could be reached

Вам сразу выдаст refused и timeout, потому что служба не запущена, и, соответственно, никто не слушает этот порт.


Нужно смотреть логи, в официальной документации есть раздел по этой теме.


Смотрим логи


logread -f -e dnscrypt-proxy

Флаг -f, как и в любых других tail подобных утилитах означает, что все свежие логи будут показываться в вашей консоли на лету.


Например, видим ошибку конфигурации


Sun Oct 16 19:28:19 2022 daemon.err dnscrypt-proxy[26781]: [2022-10-16 19:28:19] [FATAL] toml: line 869 (last key "static.server_names"): type mismatch for main.StaticConfig: expected table but found []interface {}

Это означает, что в 869 строке у нас заданы server_names в разделе statics. У меня такое было, когда не было проверки и криво отработал ansible.


Идём в конфиг
/etc/dnscrypt-proxy2/dnscrypt-proxy.toml и удаляем лишнюю строку.


Перезапускаем dnscrypt


/etc/init.d/dnscrypt-proxy restart

Проверяем


root@OpenWrt:~# nslookup itdog.info 127.0.0.1
Server:     127.0.0.1
Address:    127.0.0.1:53

Non-authoritative answer:
Name:   itdog.info
Address: 95.217.5.75

Починили


А если nsoolkup у вас выдаёт такую ошибку


root@OpenWrt:~# nslookup itdog.info 127.0.0.1
Server:     127.0.0.1
Address:    127.0.0.1:53

** server can't find itdog.info: REFUSED

** server can't find itdog.info: REFUSED

то у вас криво настроен dnsmasq для работы с DNSCrypt, правьте /etc/config/dhcp


Вторая версия DNSCrypt намного стабильнее и живучее первой, ещё и работает из коробки. Если у вас совсем всё плохо с конфигом, и уже не понятно, что наделали там, просто переустановите пакет.


Разбираемся с WireGuard


Сервер — вируталка с wg за пределами РФ, клиент — роутер с OpenWrt.


Если у вас работает всё, кроме заблокированных ресурсов, самой вероятной причиной этого будет не поднявшийся wg туннель. Давайте проверим, заходим на роутер и проверим, что интерфейс существует в прицнипе


ip a


Если интерфейса wg0 вообще нет, то он у вас просто не настроен, проверяйте /etc/config/network


Если интерфейс в статусе DOWN, то у вас что-то с WAN интерфейсом (нет доступа в интернет), DNS (если сервер указан по url) или есть ошибки в конфигурации. Это подробно разобрано ниже.


290: wg0: <POINTOPOINT,NOARP> mtu 1420 qdisc noop state DOWN qlen 1000
    link/[65534] 

Если интерфейс есть, и он в статусе UP или UNKNOWN, давайте проверим, ходит ли через него трафик с помощью ping. Укажем через какой интерфейс пинг должен идти


ping -I wg0 itdog.info

Если трафик идёт


root@OpenWrt:~# ping -I wg0 itdog.info
PING itdog.info (95.217.5.75): 56 data bytes
64 bytes from 95.217.5.75: seq=0 ttl=57 time=106.460 ms
64 bytes from 95.217.5.75: seq=1 ttl=57 time=120.917 ms
64 bytes from 95.217.5.75: seq=2 ttl=57 time=121.437 ms
^C
--- itdog.info ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 106.460/116.271/121.437 ms

то проблема не с Wireguard.


Если трафик не идёт, значит у вас что-то не то с сервером, либо конфигурацией на роутере.


Пойдём от простого к сложному. Внимательно проверьте, что:


  • Не перепутали ключи, и они верные
  • Указали верно url\ip адрес сервера и внутренний ip клиента
  • Сервер настроен в качестве шлюза
  • Если на сервере Wireguard включен preshared_key, то он должен быть задан и на клиенте

После исправления ошибки, нужно рестартовать сеть /etc/init.d/network restart


Так же можно по-старинке опускать и поднимать интерфейс


ifdown wg0
ifup wg0

Относительно простой вариант проверить, что на сервере всё ок — поставить wg на ваше устройство и попробовать конфиг для openwrt там. Обязательно на время проверки выключите wg на роутере (ifdown wg0), иначе будет коллизия. Если на клиенте у вас трафик пойдёт через wireguard, значит вы неправильно настраиваете wireguard на OpenWrt. А если не пойдёт, то либо у вас сервер неправильно настроен, либо конфигурация на клиенте тоже неверная.


Если всё перепроверили, и всё равно не работает, покажу, как копать глубже. У wireguard, помимо его неоспоримых плюсов, есть один очень жирный минус — это логирование. У того же OpenVPN в большинстве случаев несложно разобраться, в чём дело, по ошибкам в логе. У Wireguard другая логика работы, и поэтому таких удобных логов у него нет.


Команда wg show покажет статус соединения более подробно. Самая важная информация в этих двух строках:


  latest handshake: 28 seconds ago
  transfer: 404 B received, 1.03 KiB sent

Первая показывает, когда было последнее рукопожатие. По умолчанию каждые две минуты должно совершаться рукопожатие. Если у вас пошла третья минута или вообще нет такой строки, то явно что-то не так с конфигурацией wireguard или с доступом к серверу (firewall, блокировка провайдером ит.д.), об этом ниже.
Вторая строка показывает сколько трафика было отправлено и принято. Если sent есть, а received 0, то это значит, что трафик отправляется через wg интерфейс, но ничего не приходит обратно — соединение не установлено. Здесь, скорее всего, тоже проблема с конфигурацией или доступом.


Копнём поглубже


Смотрим логи на openwrt


logread -f -e wg0

Для удобства, можно открыть ещё одну консоль рядом, и сразу будет видно, что пишет wg



Также можно смотреть логи на сервере. Для этого нужно включить debug режим (под root)


modprobe wireguard
echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control

Для выключения дебаг лога нужна такая же команда, только с -p


 echo module wireguard -p > /sys/kernel/debug/dynamic_debug/control

После этого смотрим логи из dmesg на сервере


dmesg -wT | grep wireguard

Либо можно смотреть файл syslog


tail -f /var/log/syslog

Если клиентов у сервера много, грепните по внешнему ip адресу вашего роутера


tail -f /var/log/syslog | grep $IP
dmesg -wT | grep wireguard | grep $IP

Внешний IP можно получить прям с роутера


curl ifconfig.co

Рассмотрим несколько ошибок, которые могут возникнуть


Ошибка в имени сервера


Отобразится в логе OpenWrt


Sun Oct 30 06:51:32 2022 daemon.notice netifd: wg0 (23972): Name does not resolve: `test.tech-domain.club:51820'

Тут всё очевидно: домен не резолвится, допущена ошибка в endpoint_host


Нет доступа до сервера с wireguard, неверный порт ит.д.


Sun Oct 30 07:25:01 2022 daemon.notice netifd: wg0 (7558): Try again: `tech-domain.club:51820'. Trying again in 1.00 seconds...

Эту ошибку вы получите всего один раз в логе после смены endpoint_host. И если у вас закрыт порт, неверно указан адрес сервера, то постоянной ошибки в логе не будет. Узнать, что что-то не так, можно из wg show


peer: $KEY
  preshared key: (hidden)
  endpoint: $IP:51820
  allowed ips: 0.0.0.0/0
  transfer: 0 B received, 296 B sent
  persistent keepalive: every 25 seconds

Он будет отображать адрес сервера, куда вы пытаетесь подключиться, на косяк указывает лишь отсутствие handshake и 0 B в received.


Ну а тестировать открыт или закрыт UDP порт (wireguard использует UDP) — это дело неблагодарное и не даст вам точных данных.


Поэтому тут проще всего будет глянуть tcpdump на сервере


tcpdump -i eth0 host $IP and not port 22

С флагом -i передаёте внешний интерфейс, после host пишите внешний ip адрес вашего роутера, and not port 22 — чтоб не выводил ваш ssh трафик


Если соединение установлено, то должны быть сообщения такого типа с ответами от сервера для них


16:35:03.142648 IP $IP_ROUTER.51820 > $IP_VPN.51820: UDP, length 128
16:35:03.144987 IP $IP_VPN.51820 > $IP_ROUTER.51820: UDP, length 128

Если сообщение остаётся без ответа


16:35:03.142648 IP $IP_ROUTER.51820 > $IP_VPN.51820: UDP, length 128

смотрите firewall на сервере и что wg вообще включен.


А если всё пусто, значит проблема в доступе к серверу. Причины могут быть:


  • Неверно указан сервер или неправильно резолвится
  • Неверно указан порт
  • Wireguard на уровне протокола блокируется провайдером
  • Закрыт порт на стороне провайдера. Например, у cloud firewall, который примененый к виртуалке, не открыт wg порт

Неверный private_key


В логах на openwrt получите такое сообщение


Sun Oct 30 08:16:43 2022 daemon.notice netifd: wg0 (27536): Key is not the correct length or format: `$KEY='

Либо не получите никакого сообщения. Всё зависит от ошибки, которую вы допустили в ключах


На сервере


[Sun Oct 30 09:22:09 2022] wireguard: wg0: Invalid handshake initiation from $IP:51820

Неверный public_key


На клиенте так же может быть сообщение


Key is not the correct length or format:

А может и не быть, всё так же зависисит от типа ошибки.


На сервере будет ошибка


[Sun Oct 30 10:24:22 2022] wireguard: wg0: Invalid MAC of handshake, dropping packet from $IP:51820

Ошибка в preshared_key


На сервере будет повторятся такая строка


Oct 30 10:50:55 vpn kernel: [67880632.804341] wireguard: wg0: Keypair 350937 destroyed for peer 181

Строка говорит о том, что wg пытается пересоздать пары ключей и у него всё-равно не получается. Виной как раз может быть кривой preshared_key.


На клиенте, как и в двух других ошибках в ключах, может быть сообщение


Key is not the correct length or format

Неверный IP в сети wireguard


Ошибок не будет в логах на клиенте. Более того, wg show вам покажет трафик.
В логах на сервере
А если запустим пинг на роутере ping -I wg0 itdog.info, то получим ошибку, которая уже прямо скажет что у нас не так


[Tue Nov 15 17:59:10 2022] wireguard: wg0: Packet has unallowed src IP (10.7.0.3) from peer 3 ($IP:51820)

Не указан или ограничен allowed_ips


root@OpenWrt:~# ping -I wg0 itdog.info
PING itdog.info (95.217.5.75): 56 data bytes
ping: sendto: Required key not available

Таким образом трафик через wg0 просто не пойдёт, но wg соединение при этом будет.


Что-то не отработало в скрипте


Скрипт выгружает списки и рестартует сеть.
Проверьте, что списки загрузились


root@OpenWrt:~# ls -lh /tmp/lst/
-rw-r--r--    1 root     root       11.4K Oct 30 11:30 community.lst
-rw-r--r--    1 root     root        1.0M Oct 30 11:30 ip.lst
-rw-r--r--    1 root     root        1.8K Oct 30 11:30 subnet.lst

Если не загрузились, то надо вручную запускать скрипт и смотреть на вывод ошибок.
Например, может быть ошибка с сертификатом у antifilter.download


Downloading 'https://antifilter.download/list/ip.lst'
Connecting to 45.154.73.71:443
Connection error: Invalid SSL certificate

В первую очередь проверьте дату на роутере


date

Если время кривое, чекните конфигурацию


root@OpenWrt:~# uci show system.ntp
system.ntp=timeserver
system.ntp.enabled='1'
system.ntp.enable_server='0'
system.ntp.server='0.openwrt.pool.ntp.org' '1.openwrt.pool.ntp.org' '2.openwrt.pool.ntp.org' '3.openwrt.pool.ntp.org'

Так она должна выглядеть. Проверьте что ntp сервер отдаёт данные


root@OpenWrt:~# ntpd -n -w -p 0.openwrt.pool.ntp.org
ntpd: reply from 188.93.90.21: offset:+0.004344 delay:0.005661 status:0x24 strat:3 refid:0x361df9ad rootdelay:0.103670 reach:0x01

Для более глубокого копания в документации есть пункт по troubleshooting.


Проверка сертификата


Чекнем, что на стороне antifilter.download всё ок, и сертификат не протух


curl -vI https://antifilter.download/list/ip.lst --stderr - | grep "expire date"

Накрайняк, со своей стороны, вы можете отключить проверку сертификатов у curl\wget


wget --no-check-certificate


wget --no-check-certificate -P $dir $SUBNET

curl --insecure


curl --insecure -z $dir/subnet.lst $SUBNET --output $dir/subnet.lst

Списки не успевают загрузится


Ещё списки могут не загружаться при старте роутера. Такое может быть, когда скрипт запускается быстрее, чем поднимется сеть и появляется доступ в интернет. Я добавил недавно в скрипт if, которые даблчекают, загрузились ли списки. Это решило лично мою проблему, но если вашу нет, можно воткнуть цикл.


Раз говорим о списках, сразу проверим, что они загружены в sets. Посмотреть, что списки созданы


root@OpenWrt:~# nft list sets
table inet fw4 {
    set vpn_subnets {
        type ipv4_addr
        flags interval
        auto-merge
    }
    set vpn_ip {
        type ipv4_addr
        flags interval
        auto-merge
    }
    set vpn_community {
        type ipv4_addr
        flags interval
        auto-merge
    }
}

Глянуть содержимое списков


nft list ruleset | grep -A 10 vpn_ip
nft list ruleset | grep -A 10 vpn_subnet
nft list ruleset | grep -A 10 vpn_community

Теперь вы точно знаете, что списки загружены в firewall.


Так же, при выполнении скрипта, могут возникать ошибки, связанные с настройкой сети и firewall. Там обычно сразу понятно, в чём дело, а если не понятно, то просто погуглите.


Не хватает памяти на роутере


Да, это можно реализовать на слабом устройстве. Но если точно хотите, чтобы всё было ок, берите роутер как минимум с 128MB ROM и 256MB RAM. Сейчас такие роутеры не стоят космических денег. Если средств немного, лучше смотрите в сторону БУ, чем греть голову лишний раз. За 4 года я купил 4 роутера с такими характеристиками за 1500-2000р с рук.


Nftables отъедает примерно 50MB во время загрузки списков из файлов. Речь про списки ip, subnet и community.
Ещё выгруженные списки складываются в оперативку — /tmp.


Если памяти не хватает:


  • Попробуйте ip.lst заменить на ipsum.lst. Либо вообще не используйте ip/ipsum, возможно лично вам хватит чисто community.lst.
  • Можно не хранить списки в /tmp: загружать их, применять и сразу удалять с помощью скрипта.
  • Откатититься на iptables или вообще на 21 версию.
  • Попробовать vpn-policy-routing + ipset (не пробовал, но говорят рабочий вариант)
  • Вот здесь предложили использовать zram и заносить списки в скрипте

Проблема c firewall на версии 22.03.2


При запуске скрипта и рестарте firewall получаем ошибку


Firewall restart
Killed
/dev/stdin:112:19-19: Error: syntax error, unexpected end of file, expecting comma or '}'
      185.60.216.0/22
                     ^
The rendered ruleset contains errors, not doing firewall restart.
Syntax: /etc/init.d/hirkn [command]

Это был косяк в пакете firewall4, либо обновите его


opkg update && opkg install firewall4

Либо все пакеты сразу


opkg update
opkg list-upgradable | cut -f 1 -d ' ' | xargs -r opkg upgrade

Проблемы на роутерах, которые официально не поддерживаются OpenWRT


На форумах вы можете встретить высказывания, что моя инструкция не работает на 22ой версии OpenWrt. Дело в том, что люди покупали устройства, которые официально не поддерживались сообществом OpenWrt. Для этих устройств была доступна только dev версия или сборки на её основе.


Openwrt 22 стала стабильной только в сентябре 2022 года. До этого она была в разработке, и поддержку nftables sets, которые являются ключевым элементом в обходе блокировок и пришли на замену ipset, туда завезли не сразу.
Люди устанавливали dev версию, где не было поддержки sets, и, соответственно, обход блокировок не работал.
К стабильной версии разработчики это поправили.
Но есть ещё большой пласт устройств, которые официально не поддерживаются OpenWrt. Например, я знаю роутер Xioami AX3600. Под него есть неофициальная сборка, основная на ранней dev версии OpenWrt 22, и в ней не поддерживаются sets.


Какие в этом случае варианты:


  • Откатиться на iptables+ipset
  • Попросить разработчика сборки взять реализацию sets из стабильной ветки
  • Использовать пакет vpn-policy-routing. Я сам не пробовал его, но с ним есть прям инструкции, например, для AX3600. И у людей в такой ситуации это было выходом
  • Поменять роутер на официально поддерживаемый (лучший вариант)

Заключение


Я не разобрал только маркировку пакетов и пару правил firewall'a. Это стандартные вещи внутри OpenWRT, которые работают стабильно и проблем с ними не наблюдалось. Поэтому их траблшутинг рассматривать не буду.


Знаете как можно лучше или я что-то упустил? Пишите в ЛС или комментарии.


Телеграм канал, в котором публикую обновления по этой теме https://t.me/itdoginf

Комментарии (3)


  1. Bambarmia
    29.11.2022 21:21
    +4

    Это был косяк в пакете firewall4, либо обновите его

    господи, я три дня мучался с этой проблемой. Firewall зависал на загрузке списков. Начинал съедать всю память, потом вылетал с ошибкой. Пришлось из-за этого накатить версию 21. А это всего лишь в этом проблема была, а не моя ошибка... Благодарю за информацию и за инструкцию в целом


    1. eaglex
      29.11.2022 21:31

      Я тоже с этим наплясался по граблям, потом автору это сообщил и получил рецепт решения с обновлением файерволла.


  1. eaglex
    29.11.2022 21:28

    Кстати, даблчек загрузки списков не панацея. Было отключение света и сеть у провайдера поднялась спустя энное время после загрузки роутера...

    Спасибо за статью.