Маршрутизация
Вкладка маршрутизации управляет тем, как обрабатываются DNS-запросы и куда направляется трафик, совпавший с целями сета. Содержит два раздела: DNS-редирект и Маршрутизация трафика.
DNS-редирект
Перенаправляет DNS-запросы для доменов из сета на указанный DNS-сервер.
Некоторые провайдеры перехватывают DNS-ответы и подменяют IP-адреса (DNS poisoning). В результате подключение идёт на неправильный адрес, даже если домен не заблокирован напрямую. DNS-редирект отправляет запрос на альтернативный сервер, минуя перехват.
Здесь описан обычный DNS-сервер. Про зашифрованный DNS (DoH), закреплённые адреса, DNS поверх TCP и общие настройки DNS смотрите страницу DNS.
Настройка
- Включите DNS-редирект
- Выберите DNS-сервер из списка или введите IP вручную
Если не знаете, какой DNS выбрать - начните с любого из списка, кроме Google DNS (8.8.8.8). Google DNS блокируется некоторыми провайдерами в первую очередь.
Список серверов
При выборе сервера его IP автоматически подставляется в поле. Можно ввести любой другой IP вручную.
Если поле DNS-сервера пустое, редирект не будет работать, даже если он включён.
Фрагментация DNS-запроса
Переключатель Фрагментировать запрос разбивает DNS-пакет на несколько частей перед отправкой.
Используется, если провайдер анализирует содержимое DNS-пакетов даже к сторонним серверам и блокирует запросы по содержимому.
Фрагментация затрагивает только DNS-запросы доменов из текущего сета. Остальной DNS-трафик не изменяется.
Маршрутизация трафика
Направляет трафик, совпавший с целями сета, через указанный сетевой интерфейс - например, VPN, WireGuard или другой туннель.
Маршрутизация всегда уводит трафик по адресу назначения: каждое правило, которое создаёт b4, сопоставляет адреса, собранные сетом из целей по IP и из адресов, в которые resolve-ятся его домены. Исходные устройства и исходные интерфейсы сужают, чей трафик попадёт в это правило, но сами по себе трафик не выбирают. Поэтому сет с включённой маршрутизацией и без доменов и IP-адресов не уводит ничего: b4 не создаёт для него правило и пишет об этом в лог.
Чтобы отправить весь трафик устройства, оставьте устройство выбранным в разделе Исходные устройства и включите Match any IP address на вкладке Цели, IP обхода.
Режим маршрутизации определяет, что происходит с совпавшим трафиком:
| Режим | Описание |
|---|---|
| Выходной интерфейс | Отправляет совпавший трафик через сетевой интерфейс. Описан ниже. |
| Вышестоящий прокси SOCKS5 | Передаёт совпавший трафик прокси SOCKS5. См. Вышестоящий прокси SOCKS5. |
| Telegram через WebSocket (встроенный) | Перехватывает совпавший трафик Telegram и ретранслирует его через WebSocket-узел Telegram. Переключатель в разделе Настройки, Telegram делает то же для всей сети без сета. См. Telegram через WebSocket. |
| Блокировка | Отбрасывает или отклоняет совпавший трафик. См. Блокировка. |
Общая схема
Как это работает (подробно)
Маршрутизация использует policy-based routing - маршрутизацию на основе меток пакетов:
-
Сбор IP-адресов. Когда b4 видит DNS-ответ для домена из сета, он извлекает из него IP-адреса и добавляет их во внутренний IP-набор (nftables set или ipset). Пересланный или закреплённый ответ, который приносит адреса, не записанные b4 в сет в последнее время, передаётся клиенту после того, как b4 закончил обновление сета для этих адресов, поэтому следующее за ним соединение обычно идёт маршрутом сета. Каждый раз, когда b4 видит ответ, он ждёт не дольше 250 мс; если обновление занимает больше времени, например пока b4 заново применяет правила маршрутизации, ответ уходит по истечении срока, и первое соединение может пойти мимо сета. Ответ, который b4 сам получает через DNS-перенаправление сета, уходит после записи адресов, без этого ограничения. Ответы, пришедшие, пока обновление сета ждёт своей очереди, попадают в него же, поэтому пачка ответов обходится несколькими обновлениями, а не отдельным обновлением на каждый, а ответ, адреса которого записаны недавно, обычно не задерживается. При движке TUN ответ не задерживается, и первое соединение к новому адресу может уйти раньше, чем адрес окажется в наборе. IP-адреса, указанные вручную в целях сета, добавляются при загрузке конфигурации.
-
Маркировка пакетов. b4 создаёт цепочки в firewall для каждого сета:
- PREROUTING (mangle) - маркирует транзитный трафик (от устройств в сети), если IP назначения есть в наборе. Если указаны исходные интерфейсы - маркирует только трафик с этих интерфейсов.
- OUTPUT (mangle) - заново маркирует пакеты, которые b4 создаёт сам: они локальные и иначе ушли бы через обычный аплинк роутера. Он же маркирует остальной трафик, созданный роутером, если Трафик самого роутера не запрещает это.
-
Policy routing. Для маркированных пакетов создаётся правило
ip rule: пакеты с определённымfwmarkнаправляются в отдельную таблицу маршрутизации, где default route указывает на выходной интерфейс. -
Masquerade. В цепочке POSTROUTING (nat) ко всему маркированному трафику, выходящему через целевой интерфейс, применяется masquerade - исходный IP пакета заменяется на IP выходного интерфейса. Это необходимо, чтобы ответные пакеты возвращались через тот же туннель.
-
Предварительное разрешение. При включении маршрутизации b4 сразу резолвит все домены из целей сета и добавляет полученные IP в набор. Это обеспечивает маршрутизацию с первого запроса, не дожидаясь DNS-трафика через NFQUEUE. Имена разрешаются через собственный резолвер сета, если в его DNS-перенаправлении он задан; см. Запросы, которые b4 делает сам.
Настройка
- Включите Маршрутизацию
- Выберите Исходные интерфейсы - с каких интерфейсов перехватывать трафик
- Выберите Выходной интерфейс - куда направить трафик

После включения в верхней части раздела отображается диаграмма потока:
[Исходные интерфейсы] → B4 → [Выходной интерфейс] → Интернет
Диаграмма обновляется при изменении настроек.
Исходные интерфейсы
Определяют, с каких сетевых интерфейсов перехватывать трафик для маршрутизации. Отображаются как кнопки-бейджи - клик включает/выключает интерфейс.
Это входящий фильтр, и это не та же настройка, что Интерфейсы захвата в разделе Настройки, Основные, Движок пакетов, которая решает, что разбирает движок, и сравнивает интерфейс, через который пакет уходит. Рядом все три разобраны в разделе Какой интерфейс за что отвечает.
Если ни один исходный интерфейс не выбран - маршрутизация применяется ко всему приходящему трафику и, в зависимости от настройки Трафик самого роутера, к трафику, который роутер создаёт сам. Если выбран исходный интерфейс или исходное устройство, сет ограничивается трафиком, пришедшим оттуда, а собственный трафик роутера остаётся на обычном маршруте: он не приходит ни с какого интерфейса и ни от какого устройства.
Если ранее выбранный интерфейс исчез из системы (например, VPN-подключение разорвалось), он отображается красным с пометкой «stale».
Выходной интерфейс
Сетевой интерфейс, через который будет отправлен маркированный трафик:
| Интерфейс | Описание |
|---|---|
wg0, wg1 | WireGuard-туннель |
tun0, tun1 | OpenVPN-туннель |
ppp0 | PPP-соединение |
Если выбранный выходной интерфейс перестал быть доступен, появится предупреждение. Маршрутизация не будет работать, пока интерфейс не появится снова. Что происходит с трафиком сета в это время - см. Аварийное отключение.
Если выходной интерфейс - поднятый туннель (TUN/TAP или WireGuard), b4 не трогает пакеты этого сета, так же как в режиме
прокси: ни подделок, ни фрагментации, ни рассинхронизации, а также ни проверки SYN, ни эскалации по мёртвым IP, ни
определения блокировки по IP, ни дублирования TCP. Изменялся бы внутренний пакет, который на роутере заворачивается или
обрывается ещё до того, как его увидит сеть, - пользы никакой, а процессор тратится на каждом соединении. Соединение
по-прежнему видно в журнале соединений с пометкой routed-><iface>. Стратегию обхода сохраняют три случая: сет,
маршрутизированный в обычный интерфейс (например, во второй аплинк); сет, у которого выходной интерфейс есть, но он не
поднят, то есть везти трафик всё равно некому; и сет «только по домену» без IP-целей, который тоже ничего не
маршрутизирует. Сет, ограниченный исходным интерфейсом или устройством, отдаёт пакеты так же, как любой другой: движок
сопоставляет только адрес назначения и не может отличить клиента в области действия сета от клиента, которого правила
маршрутизации не касаются.
Трафик самого роутера
Идут ли через выходной интерфейс соединения, которые роутер открывает сам - обновление пакетов, проверка доступности, DNS-резолвер, другая программа на этой же коробке, - когда они адресованы чему-то из сета. Транзитный трафик из сети эта настройка не затрагивает.
| Значение | Что происходит |
|---|---|
| Автоматически (по умолчанию) | Трафик роутера маршрутизируется, кроме случая, когда выходной интерфейс - устройство TUN/TAP, которое читает программа в пользовательском пространстве. Там он остаётся на обычном маршруте. |
| Тоже маршрутизировать | Маршрутизируется всегда. |
| Не трогать | Не маршрутизируется никогда. |
Исключение существует из-за петли. Прокси с TUN-входом - Xray, sing-box, клиент вида tun2socks - пакет не пересылает: он
обрывает соединение и открывает своё к адресу назначения, с этого же роутера. Это новое соединение адресовано тому же
адресу из сета, поэтому b4 помечает его и отправляет обратно в тот самый TUN, который прокси и читает. Прокси отвечает на
него точно так же, и так далее. Каждый виток идёт с нового исходного порта, поэтому ядро не распознаёт в нём повтор, и
каждый виток стоит прокси ещё одной сессии и ещё одного сокета. На практике память на коробке кончается за минуты.
Такой интерфейс b4 узнаёт по /sys/class/net/<iface>/tun_flags - этот файл ядро создаёт для каждого устройства,
открытого через /dev/net/tun. WireGuard, PPP, VLAN и физические интерфейсы это не затрагивает: они не могут открыть
соединение заново, поэтому на Автоматически трафик роутера продолжает следовать за сетом.
Выбрать Тоже маршрутизировать для TUN-интерфейса можно - TUN, читатель которого никогда не ходит к адресу назначения
напрямую, безвреден, - но b4 запишет предупреждение и поставит перед маркировкой ограничение скорости, так что начавшаяся
петля упрётся в 200 новых соединений роутера в секунду на каждый список адресов и не разгонится. Ограничение считает
только соединения к адресам, которые сет сопоставляет, - обычный трафик роутера его бюджет израсходовать не может. Оно
ставится там, где выход может открыть соединение заново: на устройстве TUN или TAP, а также на интерфейсе, который b4 ещё
не может определить, потому что на момент построения правил его нет. Обычный интерфейс и туннель WireGuard его не
получают. На iptables нужен модуль xt_hashlimit: b4 загружает его сам и предупреждает, если в ядре его нет.
Сет, у которого уже выбран исходный интерфейс или включающий список исходных устройств, трафик самого роутера не маршрутизирует никогда, что бы здесь ни стояло, - поэтому настройка показана неактивной. Исключающий список так сет не ограничивает, и там выбор по-прежнему действует.
Если вы маршрутизируете сет в TUN прокси, а прокси настроен ходить к части этих адресов напрямую (outbound
freedom/direct, правило обхода, собственный DNS), - это ровно та самая петля. Для такого случая и предназначено
значение Автоматически.
Аварийное отключение
По умолчанию выключено. Когда выходной интерфейс пропадает - туннель оборвался, VPN-клиент перезапустился, - ядро убирает маршрут по умолчанию, который b4 положил в таблицу сета. Правило по метке находит пустую таблицу, поиск проваливается в основную таблицу, и трафик сета тихо уходит через обычный аплинк с настоящим адресом роутера. В правилах при этом ничто не выглядит неправильным - потому это легко и не заметить.
Со включённым аварийным отключением b4 держит в таблице сета маршрут blackhole default с худшей метрикой, чем настоящий.
Пока интерфейс поднят, выигрывает настоящий маршрут и ничего не меняется. Когда интерфейс пропадает, остаётся только
blackhole, и трафик сета отбрасывается, а не утекает. Затронут только трафик этого сета; всё остальное продолжает
пользоваться основной таблицей как обычно. Сеты с общим выходным интерфейсом обычно делят одну таблицу маршрутизации,
поэтому сету со включённым аварийным отключением выделяется собственная таблица, чтобы он не отбрасывал трафик соседей.
Это касается таблиц, которые b4 назначает сам; два сета, вручную закреплённых за одной routing.table, её по-прежнему
делят, и тогда отключение работает для обоих, если включено хотя бы у одного.
Настоящий маршрут b4 возвращает сразу, как только интерфейс появляется снова, поэтому после переподключения аварийное отключение не нужно выключать и включать заново.
Egress IP
Необязательный параметр. Подменяет адрес источника у трафика этого сета на выходе, вместо того чтобы оставлять собственный адрес выходного интерфейса. В терминах firewall это замена правила MASQUERADE на SNAT --to-source для этого сета.
Смысл в том, чтобы передать решение о маршруте устройству, которым b4 не управляет. Если туннели подняты на вышестоящем роутере, этот роутер уже умеет выбирать путь по адресу источника, и b4 достаточно проставить нужный источник. На хосте самого b4 не нужны ни интерфейс туннеля, ни отдельная таблица маршрутизации, а в отличие от вышестоящего SOCKS5-прокси подмена выполняется в ядре и не тратит CPU на каждый пакет.
Egress IP требует выходного интерфейса: правило привязывается к нему, чтобы при переключении на второй WAN пакеты не ушли в другой аплинк с адресом источника от первого.
Чтобы это заработало целиком:
- b4 сам добавляет адрес на выходной интерфейс и убирает его, когда сет перестаёт им пользоваться, так что вручную ничего добавлять не нужно и сохранять между перезагрузками тоже. Если интерфейс потерял адрес, например при обновлении аренды DHCP или подъёме линка, b4 это замечает и возвращает адрес на место. Прежде чем занять адрес, b4 отправляет ARP-пробу; если на него отвечает другой хост сегмента или адрес не удаётся добавить, b4 пишет предупреждение и возвращается к masquerade, вместо того чтобы сломать этот хост или отправлять трафик, на который никто не ответит. Адрес, настроенный вами вручную, используется как есть, и b4 удаляет только те адреса, которые добавил сам.
- Вышестоящее устройство должно маршрутизировать этот источник в нужный путь, например
ip rule add from 192.168.1.51 lookup 100в Linux или правилоmangleсsrc-addressиaction=mark-routingв RouterOS. - Вышестоящее устройство не должно отбрасывать пакеты на проверке обратного пути. Роутер со строгим
rp_filterи без маршрута обратно к машине с b4 для этого адреса отбросит их до того, как дойдёт до правил политики. Это самая частая причина, по которой внешне верная настройка не пропускает трафик.
Семейство адресов должно совпадать. IPv4-адрес подменяет только IPv4. Что при этом произойдёт с IPv6-трафиком сета, зависит от Поддержки IPv6 в Настройки, Основные, Движок пакетов:
- Поддержка IPv6 включена. IPv6-трафик сета по-прежнему уводится на выходной интерфейс, работает через masquerade и уходит с собственным IPv6-адресом интерфейса. У сета один egress IP, поэтому IPv6-адрес на его месте переносит подмену на IPv6, а IPv4 возвращается к masquerade.
- Поддержка IPv6 выключена. У сета вообще нет IPv6-правил. Его IPv6-трафик не маркируется, не уводится и не проходит masquerade: он идёт обычным маршрутом роутера, а для назначения с двойным стеком это значит, что сет обходится стороной, а не маршрутизируется с неверным адресом источника.
Egress IP, на который никто не отвечает, ломает трафик молча: пакеты уходят, ответы не возвращаются, а правила сета при этом выглядят корректно. Прежде чем искать проблему в сете, проверьте, что адрес есть на интерфейсе.
Недоступно в режиме движка TUN с захватом всего маршрута по умолчанию. Там b4 переотправляет пакеты по пути, который обходит это правило, и настройка не действует.
IP TTL (время жизни записи)
Определяет, сколько секунд IP-адрес, полученный из DNS-ответа, хранится в IP-наборе маршрутизации. По истечении TTL запись удаляется автоматически.
Значение по умолчанию: 3600 секунд (1 час).
IP-адреса, указанные в целях сета, хранятся постоянно: они записываются при каждой синхронизации конфигурации и удаляются из набора ядра, когда их убирают из целей.
Для стабильных сервисов с постоянными IP можно увеличить TTL. Для CDN-сервисов, где IP меняются часто, лучше уменьшить.
Firewall backend
| Backend | Требования | Описание |
|---|---|---|
| nftables | бинарник nft | Создаёт таблицу b4_route с цепочками prerouting, output, postrouting. IP-наборы с поддержкой interval и timeout. |
| iptables + ipset | бинарники iptables, ipset | Использует таблицы mangle и nat. Создаёт ipset типа hash:net для хранения IP. Также проверяет iptables-legacy. |
Маршрутизация работает на backend из настройки Движок файрвола, а при Автоопределении - на том, который b4 выбрал для остальных своих правил. На iptables маршрутизации нужен ещё бинарник ipset. Без него, как и без бинарника iptables, маршрутизация переходит на nftables, если есть бинарник nft, даже когда проверка nftables при Автоопределении не прошла. Если не подходит ни один backend, b4 не ставит ни одного правила маршрутизации. В Docker-образе b4 есть все три: nft, iptables и ipset.
Пока ни у одного включённого сета не включена маршрутизация и выключен переключатель «Telegram через WebSocket», для маршрутизации не создаётся ничего, даже таблица b4_route.
Если правила не ставятся
b4 ставит правила маршрутизации при запуске, при каждом сохранении конфигурации и когда монитор файрвола не находит их на месте. Если backend отвергает основу правил, например таблицу b4_route, не ставится ни один сет, а в логе появляется строка:
[ERROR] Routing: failed to ensure base during sync (nftables): ensure table: ..., it will be retried
Если не ставятся только некоторые сеты, о каждом из них пишется отдельная строка, Routing: failed to ensure rule for set '<name>' during sync: ..., а остальные сеты ставятся.
Дальше b4 повторяет попытку сам. Первый повтор идёт через 10 секунд после ошибки, после каждого неудачного повтора пауза удваивается: 20, 40, 80, 160 и 320 секунд; затем b4 повторяет попытку каждые 10 минут, пока она не удастся. Свои строки повторы пишут на уровне trace, и в логе они видны только при уровне логирования trace или debug. На уровне info от цикла остаются три строки:
| Строка | Уровень | Когда |
|---|---|---|
Routing: failed to ensure base during sync ... или Routing: failed to ensure rule for set ... | ERROR | Первая ошибка для этой конфигурации |
Routing: the routing sync keeps failing; b4 retries it every 10m0s ... | WARN | Не удался шестой повтор, через 10 минут 30 секунд после первой ошибки |
Routing: the routing sync that failed has been retried successfully | INFO | Повтор удался |
Сохранение конфигурации или перезапуск начинают цикл заново: снова строка ERROR и первый повтор через 10 секунд. Пока после ошибки на основе правил ждёт повтор, монитор файрвола не трогает правила маршрутизации и при каждой проверке пишет на уровне trace Monitor: a newer routing configuration is waiting to be retried, leaving routing alone this tick.
Если в ядре нет того, что нужно backend, например семейства inet у nftables или модуля ip_set для iptables, каждый повтор заканчивается той же ошибкой, и удаться повтор может только после смены ядра или backend.
Если не подходит ни один backend или нет команды ip, b4 пишет предупреждение при каждом запуске и сохранении, ничего не ставит и попыток не повторяет. Наличие этих команд b4 проверяет один раз за запуск, поэтому установленная позже утилита начинает действовать после перезапуска.
Строка Сеты маршрутизации раздела Firewall в окне Информация о системе показывает, сколько сетов с включённой маршрутизацией установлено, и backend. Пока правила не ставятся, строки под ней дают ошибку или ошибку каждого не установленного сета, время начала сбоя и время следующей попытки, а также называют недостающую утилиту, обычно ipset, если из-за её отсутствия маршрутизация идёт через nftables.
FWMark и таблица маршрутизации
Каждому сету с выходным интерфейсом автоматически назначаются:
- fwmark - метка пакета: из хеша в диапазоне
0x100-0x7EFF, а если все такие значения заняты, перебором начиная с0x66 - routing table - номер таблицы маршрутизации (диапазон
100-249)
Значения вычисляются на основе имени интерфейса, адреса источника и настройки аварийного отключения и остаются стабильными между перезагрузками. Сеты, у которых совпадают все три, разделяют fwmark и таблицу; сет, отличающийся хотя бы одним - например, со включённым аварийным отключением рядом с выключенным, - получает свои.
Прежде чем занять таблицу, b4 проверяет, нет ли в ней маршрутов, которые положил не он (в том же диапазоне лежат таблицы,
которые Asuswrt-Merlin отдаёт своим VPN-клиентам), и пропускает таблицы, названные в файлах rt_tables
(/etc/iproute2/rt_tables с rt_tables.d/*.conf, а также такие же файлы в /opt/etc/iproute2, /usr/share/iproute2 и
/usr/lib/iproute2) или указанные в ip rule другого сервиса. Если таблица занята, b4 берёт следующего кандидата и пишет в журнал, какой именно.
При уборке b4 удаляет из таблицы только маршруты, которые добавил сам.
Ручное указание fwmark и table доступно через конфигурационный файл. Они применяются, если заданы оба, метка лежит внутри 0x27FFF, не равна 0x24BAB (метка Telegram через WebSocket, которую b4 убирает из сета), не содержит всех битов метки очереди и не равна её битам под 0x27FFF; иначе b4 назначает свои.
Все метки, правила ip rule и таблицы, которые ставит b4, и значения некоторых других сервисов на роутере перечислены на странице Метки пакетов.
Очистка
При отключении маршрутизации или удалении сета b4 полностью удаляет все созданные правила:
- Удаляет
ip ruleи записи в таблице маршрутизации - Удаляет jump-правила из базовых цепочек
- Очищает и удаляет созданные цепочки и IP-наборы
При полной остановке b4 выполняется очистка обоих backend (nftables и iptables) для удаления возможных остаточных правил.
Вышестоящий прокси SOCKS5
Вместо отправки совпавшего трафика через интерфейс b4 может передать его прокси SOCKS5. Установите Режим маршрутизации в Вышестоящий прокси SOCKS5.
Так b4 включается в цепочку с Xray, sing-box или подобным клиентом - работающим как на самом роутере, так и на другом хосте в сети. Режим полезен и там, где блокировка построена по принципу белого списка и прямые соединения к адресам вне списка отбрасываются.
Как это работает
-
Сбор IP. Источники те же, что и в режиме интерфейса: DNS-ответы, которые видит b4, статические IP из целей сета и предварительное разрешение доменов сета. Кроме того, имя, совпавшее с сетом по суффиксу домена, разрешается целиком, поэтому все его адреса попадают в набор сразу, а не узнаются по одному соединению за раз. Адрес, который b4 узнаёт из SNI в TLS ClientHello, а не из DNS-ответа, попадает в набор только после того, как соединение с этим ClientHello уже ушло напрямую; следующие соединения к этому адресу перехватываются.
-
Прозрачный слушатель. b4 открывает слушателя на порту, вычисленном из сета, и помечает сокет прозрачным, чтобы принимать соединения, адресованные другому узлу.
-
Перехват. Правила TPROXY в PREROUTING направляют TCP, а при включённой опции Маршрутизировать UDP через upstream и UDP, с адресом назначения из набора на этот слушатель вместе с
ip ruleи локальным маршрутом, чтобы пакет доставлялся локально, а не пересылался дальше. Адреса самого роутера, широковещательные и групповые адреса не перехватываются никогда, поэтому сет, совпадающий с любым адресом, оставляет привязанному к нему устройству доступ к DNS, DHCP и веб-интерфейсу роутера. -
Ретрансляция. Для каждого принятого соединения b4 открывает SOCKS5 CONNECT к вышестоящему прокси и передаёт байты в обе стороны.
В режиме прокси манипуляции с пакетами (подделка, фрагментация, десинхронизация) для совпавшего трафика отключены. За доставку до назначения отвечает вышестоящий прокси.
Требования
Прозрачный перехват требует модулей ядра, которых нет в установке OpenWrt по умолчанию:
opkg install kmod-nft-tproxy kmod-nft-socket
На сборках с apk:
apk add kmod-nft-tproxy kmod-nft-socket
В системе с iptables соответствующие модули - kmod-ipt-tproxy и kmod-ipt-socket, а также iptables-mod-tproxy для самого расширения iptables. На Keenetic эти модули входят в прошивку в /lib/modules и загружаются самим сервисом; устанавливать ничего не требуется.
Правило, которое не даёт перехватывать адреса самого роутера, использует сопоставление по типу адреса: kmod-ipt-extra вместе с iptables-mod-extra в системе с iptables, kmod-nft-fib на nftables. Там, где это сопоставление отклоняется, сервис записывает вместо него явный список адресов роутера, обновляемый при следующей пересборке сета, и сообщает об этом в логе.
Кнопка Информация о системе в разделе Настройки, Система, Сервис показывает в разделе Возможности ядра, доступен ли TPROXY, и называет пакеты с недостающими модулями.
Bridge netfilter
Когда net.bridge.bridge-nf-call-iptables равен 1, ядро прогоняет правила IPv4 из PREROUTING для трафика, который входит через сетевой мост (bridge), например br-lan или docker0 от Docker, прямо в коде моста и не прогоняет их повторно, когда пакет доходит до уровня IP. Правило TPROXY привязывает соединение к слушателю b4 именно в этом проходе, а уровень IP сбрасывает привязку, когда мост передаёт ему пакет. Метка маршрутизации при этом сохраняется, поэтому пакет всё равно доставляется локально, но его не принимает ни один сокет, а ответить от исходного адреса назначения ядро тоже не может. Соединения устройств за мостом висят до таймаута, и строк о соединениях для них в логе b4 нет. Соединения, которые открывает сам роутер, через мост не проходят и перехватываются как обычно. net.bridge.bridge-nf-call-ip6tables делает то же самое для IPv6. Кроме того, у каждого моста есть собственные атрибуты nf_call_iptables и nf_call_ip6tables в /sys/class/net/<bridge>/bridge/. Ядро выполняет этот проход, если 1 стоит либо в глобальной настройке, либо в атрибуте моста, поэтому 0, записанный в атрибут, выключает проход для этого моста только при глобальной настройке, тоже равной 0.
На OpenWrt обе настройки включает при загрузке пакет dockerd через файл /etc/sysctl.d/12-br-netfilter-ip.conf. Выключаются они без перезагрузки командами:
sysctl -w net.bridge.bridge-nf-call-iptables=0
sysctl -w net.bridge.bridge-nf-call-ip6tables=0
Чтобы значение пережило перезагрузку (кроме двух конфигураций Docker, описанных ниже), те же строки добавляются в /etc/sysctl.conf, который применяется после файлов из /etc/sysctl.d:
printf 'net.bridge.bridge-nf-call-iptables=0\nnet.bridge.bridge-nf-call-ip6tables=0\n' >> /etc/sysctl.conf
С выключенным bridge netfilter контейнеры в сети Docker, созданной с icc=false, перестают быть изолированы друг от друга, а при отключённом userland proxy Docker контейнер не достаёт до портов, которые публикуют другие контейнеры той же сети. Конфигурация Docker в OpenWrt по умолчанию не использует ни то, ни другое. В обеих конфигурациях dockerd сам снова выставляет net.bridge.bridge-nf-call-iptables в 1 всякий раз, когда настраивает затронутую сеть, в том числе при каждом своём запуске, который на OpenWrt происходит уже после применения sysctl при загрузке, а для сети с IPv6 делает то же с net.bridge.bridge-nf-call-ip6tables, поэтому выключенными эти настройки там не остаются.
Пока bridge netfilter включён для моста с портами и активен сет в этом режиме или в режиме «Telegram через WebSocket» либо переключатель «Telegram через WebSocket», сервис пишет в лог предупреждение с именем моста и настройкой, которую нужно изменить. Окно Информация о системе в разделе Настройки, Система, Сервис показывает то же в строке Bridge netfilter раздела Firewall, а карточка «Telegram через WebSocket» при включённом переключателе показывает предупреждение.
Настройки
| Настройка | Описание |
|---|---|
| Хост вышестоящего SOCKS5 | Имя хоста или IP прокси. Укажите 127.0.0.1, если он работает на том же роутере, или адрес другого хоста в сети. |
| Порт вышестоящего SOCKS5 | Порт, который слушает прокси. |
| Имя пользователя / Пароль | Заполняются только если прокси требует аутентификацию. |
| Передавать имя домена в upstream | Передаёт имя хоста вместо адреса, когда его удаётся связать с соединением, чтобы прокси разрешил имя сам и выбрал подходящий по географии адрес. См. Имя назначения. |
| Маршрутизировать UDP через upstream | Туннелирует совпавший UDP через прокси по UDP ASSOCIATE. См. QUIC и HTTP/3 ниже. |
| Откат на прямое соединение при отказе прокси | Открывает обычное прямое соединение к исходному адресу, когда прокси недоступен, вместо отказа. Оставьте выключенным, если прямое соединение хуже, чем никакого. |
QUIC и HTTP/3
Большинство прокси SOCKS5 передают только TCP. Xray и sing-box требуют явно включить UDP на входящем подключении.
При выключенной опции Маршрутизировать UDP через upstream b4 отклоняет совпавший UDP на порту 443 через ICMP port-unreachable. Браузеры читают это как сигнал откатиться на TCP, который прокси передаёт. Без этого любой сайт, объявляющий HTTP/3 заголовком alt-svc, открывался бы по QUIC напрямую, минуя прокси, а браузер запоминает такой выбор на весь срок жизни, указанный в заголовке.
Этот отказ пишется отдельно для каждого семейства адресов. IPv6-половина появляется, только когда включена Поддержка IPv6 в Настройки, Основные, Движок пакетов. При выключенной поддержке создаётся только IPv4-правило, поэтому совпавшее с сетом назначение, отвечающее ещё и по IPv6, по-прежнему доступно там по QUIC, и такое соединение через прокси не идёт.
При включённой опции совпавший UDP уходит к прокси через UDP ASSOCIATE. Включайте её, только если вышестоящий прокси это умеет. Если не умеет, совпавший UDP отбрасывается, а b4 пишет предупреждение с именем сета и адресом прокси.
Имя назначения
При включённой опции Передавать имя домена в upstream SOCKS5 CONNECT несёт имя хоста вместо адреса назначения всякий раз, когда b4 может связать имя с соединением, и прокси разрешает это имя сам.
Если соединение начинается с TLS ClientHello или обычного HTTP-запроса, имя из него (SNI или Host) передаётся, только если его что-то подтверждает: DNS-ответ для этого адреса, который b4 видел за последние 30 минут, неважно для какого устройства или для самого b4 при разрешении доменов одного из сетов, или список доменов самого сета. В остальных случаях соединение идёт по адресу. VLESS Reality, ShadowTLS и fake-TLS прокси Telegram подключаются к одному адресу и предъявляют имя постороннего сайта, и передача такого имени увела бы соединение на этот посторонний сайт.
Если в соединении нет имени, которое можно прочитать, как у протоколов, где первым говорит сервер (SMTP, IMAP, FTP), имя берётся, по порядку: из DNS-ответа, по которому это устройство получило этот адрес, из имени, выученного раньше по ClientHello, совпавшему с сетом, и из имени, которое b4 сам разрешил для доменов этого сета. Имена, которые запрашивали другие устройства, и имена, которые b4 разрешил для других сетов, для такого соединения не используются.
Пока хотя бы один proxy-сет передаёт имена, b4 запоминает имя из вопроса каждого ответа A и AAAA на UDP-порту 53, который отвечает на увиденный им запрос, а также ответов, которые он сам собирает для DNS-перенаправления сета. Закреплённые ответы не запоминаются, а имя, закреплённое в DNS-настройках сета, всегда идёт по адресу, чтобы прокси не разрешил его во что-то кроме закреплённого адреса.
Чтобы прочитать ClientHello, b4 ждёт первых байтов соединения до отправки CONNECT. Клиент, который говорит первым, присылает их сразу. Соединение, в котором первым говорит сервер, ждёт 250 мс, кроме случаев, когда это устройство получило для адреса ровно одно имя или когда прочитанное имя всё равно нечем подтвердить: для адреса нет DNS-ответа, а в сете нет доменов.
Если прокси отказывает в имени, например выходной узел Tor не может его разрешить, b4 повторяет CONNECT с адресом.
Опция относится к TCP. UDP через UDP ASSOCIATE всегда передаёт адрес.
С SafeSocks 1 Tor отклоняет соединение, полученное по адресу, и пишет в лог Your application (using socks5 to port 443) is giving Tor only an IP address. Соединения без имени, которое b4 может подтвердить, по-прежнему приходят по адресу, например с устройства, которое разрешает имена через DoH, DoT или «Частный DNS» Android и открывает адрес, совпавший по целям IP, CIDR или GeoIP, под именем, которого нет в сете. SOCKS-порт Tor не поддерживает UDP ASSOCIATE, поэтому сет, направленный в Tor, работает с выключенной опцией Маршрутизировать UDP через upstream.
Соединения через встроенный SOCKS5-прокси
Клиент собственного SOCKS5-прокси b4, который запрашивает имя хоста, совпадающее с сетом, передаётся в upstream сета напрямую, без правил файрвола. CONNECT к upstream несёт это имя по тем же правилам, что описаны выше: имя, закреплённое в DNS-настройках сета, идёт по закреплённому адресу, при выключенной опции Передавать имя домена в upstream b4 разрешает имя сам и передаёт адрес, а имя, которое upstream отклонил, повторяется с адресом. Для этих запросов используется собственный резолвер сета, если в его DNS-перенаправлении он задан, а иначе резолвер роутера; см. Запросы, которые b4 делает сам. Имя .onion никогда не разрешается локально и никогда не уходит в прямое соединение. Откат на прямое соединение при отказе прокси срабатывает, когда upstream недоступен, а не когда он отклоняет назначение.
Это не зависит от того, видел ли b4 DNS-ответ для имени. Так это работает и в режиме TUN, где ответы на собственные запросы роутера до b4 не доходят, и для имён, у которых нет адреса вне upstream, например .onion в Tor.
Решает первый сет, совпавший с именем, как и для DNS-ответа. Передача касается сета в режиме прокси, у которого работает слушатель, который принимает собственный трафик роутера (не ограничен исходными интерфейсами или включающим списком исходных устройств) и не использует сопоставление только по домену. Запрос по адресу и имя, которое решающий сет не покрывает, открывает сам роутер, и такое соединение проходит через правила файрвола, как любое другое соединение роутера.
Сет, который захватывает собственный upstream
Proxy-сет перенаправляет и соединения, которые сам роутер открывает к адресам из сета. Вышестоящий прокси, работающий на роутере, открывает соединение к своему серверу тоже с роутера, поэтому сет, в цели которого попадает адрес этого сервера, например 0.0.0.0/0 или широкая категория GeoIP, отдал бы прокси его же соединение, и оно ушло бы по кругу. b4 распознаёт такое соединение по процессу, которому оно принадлежит: тому, что держит слушающий сокет на порту вышестоящего прокси. Это соединение уходит прямо к назначению, а не в прокси. Хост прокси, заданный именем, для этой проверки разрешается, а 0.0.0.0 считается самим роутером.
Процессы прокси на другом устройстве в сети b4 не видит. Соединение с такого устройства уходит напрямую в двух случаях: сет нацелен на 0.0.0.0/0 или ::/0, либо b4 в этот момент ведёт через этот прокси соединение к тому же назначению, и это собственное исходящее соединение прокси вернулось обратно. Всё остальное с этого устройства проходит через прокси как обычно. Прокси на другом устройстве, адрес сервера которого попадает в широкий GeoIP-сет, не распознаётся; сет, из исходных устройств которого это устройство исключено, его трафик не трогает.
При первом таком случае лог называет сет и процесс, а для прокси на другом устройстве - адрес этого устройства.
Собственный трафик прокси при этом всё равно проходит через b4. Метка на исходящих сокетах прокси полностью выводит его из-под перенаправления сета: цепочки прокси пропускают любой пакет, в метке которого есть бит внутри 0x27FFF, например sockopt.mark со значением 255 на исходящем подключении Xray. Какие биты читает b4, см. на странице Метки пакетов.
Как проверить работу
Не судите по тому, отрисовалась ли веб-страница. Страница обычно подтягивает ресурсы с других имён и других адресов, поэтому страница, у которой основной документ маршрутизируется, а ресурсы нет, может выглядеть сломанной, хотя маршрутизация работает верно.
Запросите одну конечную точку:
curl -s https://ipinfo.io/ip
Затем посмотрите в журнале соединений нужную запись. Трафик, прошедший через прокси, помечен [proxy]:
TCP 192.168.1.37:20854 → 34.117.59.81:443 ipinfo.io sni-set=ipinfo.io [proxy]
Имя в строке есть независимо от того, включено ли Передавать имя домена в upstream. Это имя, которое b4 уже связывает с адресом, из DNS-ответа устройства (пока настройка включена) или из более раннего соединения, а если такого имени нет, то SNI или заголовок Host самого соединения. Поле tls= появляется, только если b4 прочитал ClientHello. У соединения, где нет ни того, ни другого, имени нет.
Если строки [proxy] нет, соединение не было перехвачено. Обычная причина - адрес, к которому оно шло, отсутствует в наборе.
Когда не отвечает сам upstream
Строка [proxy] говорит лишь о том, что соединение дошло до b4, но не о том, что прокси ответил. Если upstream отклоняет соединения или молча их отбрасывает, каждое перехваченное соединение принимается, удерживается всё время ожидания подключения и закрывается - из браузера это выглядит как зависший и так и не открывшийся сайт.
b4 сообщает об этом в журнале:
tproxy: set "TMDB" cannot reach its upstream 10.8.0.1:1080 (1 consecutive failures),
traffic matched by this set is not getting through: dial upstream: dial tcp 10.8.0.1:1080: i/o timeout
Пока upstream недоступен, сообщение повторяется не чаще раза в минуту, а когда он снова отвечает - в журнал попадает парная запись. То же состояние есть в разделе upstreams диагностики, которую копирует кнопка Копировать JSON в окне Информация о системе (Настройки, Система, Сервис), поэтому по диагностическому отчёту видно, был ли прокси доступен на момент его снятия:
{
"set_name": "TMDB",
"upstream": "10.8.0.1:1080",
"reachable": false,
"consecutive_failures": 12,
"last_error": "dial upstream: dial tcp 10.8.0.1:1080: i/o timeout"
}
Учтите, что это касается каждого адреса в сете и всех TCP-портов - включая адреса, выученные с общего CDN, на который разрешаются и посторонние сайты. Поэтому недоступный upstream способен сломать сайты, ради которых сет не создавался.
Если клиент разрешает имена через DNS-over-HTTPS или DNS-over-TLS, b4 не видит его DNS-запросов, и набор наполняется только предварительным разрешением и доменами из TLS-рукопожатий. Отключите шифрованный DNS на клиенте либо добавьте домены в сет, чтобы они разрешались заранее.