Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок

в 5:16, , рубрики: OpenWrt, sing-box, tproxy, обход блокировки, обход блокировок

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

Требования к оборудованию

  • OpenWrt 24.10.0 или новее.

  • Не менее 256 МБ ОЗУ.

  • Не менее 64 МБ ПЗУ (я не проверял на 64 МБ — зависит от того, сколько занимает система для вашего роутера; 128 МБ точно хватит). В теории можно упаковать исполняемый файл sing-box с помощью UPX, но это может увеличить расход оперативной памяти.

  • На Filogic 820 примерная пропускная способность — 600–800 Мбит/с. На MT7621 должно получиться не менее 100 Мбит/с, возможно больше.

Перенаправление трафика в sing-box. OpenWrt-Momo

Большинство руководств, которые я видел, предполагают использовать софт, в котором маршрутизация происходит до sing-box (например, Podkop или RuAntiBlock).
Если пользователь хочет проводить всю маршрутизацию силами sing-box или xray, обычно предлагается самостоятельно создавать все необходимые правила перенаправления трафика, как в этом руководстве. Это сложно и неудобно (что если вы не хотите направлять весь трафик, а только от определённых клиентов локальной сети или на определённые порты?). Я пробовал настраивать это вручную ещё в 2024 году, у меня ничего не получилось и я надолго забросил эту идею.

Недавно обнаружил, что китайские разработчики сделали пакет для OpenWrt, который делает ровно то, что нужно: направляет трафик в sing-box, позволяя ограничить перенаправляемый трафик по целевым портам и по источникам в локальной сети. Также этот софт может получать настройки из внешнего источника (получает файл конфига по ссылке; для безопасности можно использовать HTTP Basic Authorization).

Итак, рассмотрим интерфейс китайского пакета Momo для OpenWrt:

Главная страница.
Здесь есть кнопки для перезагрузки конфигурации и полного перезапуска сервиса.

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 1
  • Choose Profile: выбрать из настроенных профилей.

  • Start Delay: задать задержку запуска после старта устройства.

  • Scheduled Restart: создать cron-задачу для перезапуска сервиса по расписанию (основное назначение - очистка лога sing-box, поскольку он сбрасывается только после перезапуска сервиса).

  • Test Profile: перед запуском профиля выполняет sing-box check для проверки корректности конфига.

  • Fast Reload: при изменении конфига вместо перезапуска sing-box заставляет текущий процесс перечитать конфиг.

  • Core Only: отключает все функции перенаправления и просто запускает sing-box.

Загрузка файлов конфига с устройства, их удаление или добавление подписки.

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 2

Интерфейс для добавления подписки.

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 3

Вкладка, дающая возможность редактировать конфиги прямо из интерфейса.

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 4

Вкладка с логами самого Momo и sing-box.

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 5

Главная функциональная вкладка для настройки перенаправления трафика в sing-box.

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 6
  • IPv4 DNS Hijack и IPv6 DNS Hijack: перехват IPv4/IPv6 DNS-запросов и их направление в sing-box. Авторы рекомендуют включать оба, если вы планируете обрабатывать DNS силами sing-box: даже если у вас нет IPv6-интернета, локальные компьютеры всё равно могут делать DNS-запросы к роутеру по IPv6 (через link-local).

  • IPv4 Proxy и IPv6 Proxy: перенаправление IPv4 и IPv6 трафика в sing-box. IPv6 можно выключить, если у вас его нет.

  • Fake-IP Ping Hijack: в sing-box есть механизм выдачи вместо реальных IP адресов адресов из заданного диапазона (fake-IP) для доменов, которые нужно обрабатывать внутри sing-box. На слабых устройствах можно выдавать адреса из этого диапазона и перенаправлять только запросы к этим адресам в sing-box. Эта опция позволяет возвращать реальный ping до конечного адреса, а не 1 мс до самого роутера. Если вы не настраивали Fake-IP, вам это не нужно, далее я не буду касаться настройки Fake-IP.

  • TCP Mode: режим перенаправления для TCP-трафика. Нам нужен TPROXY, т.к. TUN гораздо более затратен по CPU для sing-box.

  • UDP Mode: режим перенаправления для UDP-трафика. Также предпочитаем TPROXY по тем же причинам.

Позволяет по различным критериям включить или отключить перенаправление трафика, источником которого является сам роутер в sing-box. Я просто выключил.

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 7

Позволяет по IPv4 / IPv6 / MAC клиента включить или отключить для него перенаправление трафика или перехват DNS-запросов.

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 8

Приоритет правил - от первого к последнему, таким образом, если вы хотите включить для всех, кроме какого-то хоста, делайте так:

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 9

А если только для определённого хоста то так:

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 10

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

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 11
  • Bypass China Mainland IP: опция, не нужная нам (не направляет трафик к китайским подсетям в sing-box).

  • Destination TCP Port to Proxy: направление в sing-box только части целевых TCP-портов. Используется, чтобы не нагружать sing-box торрент-трафиком (для большого количества соединений требуется много ОЗУ; при 256 МБ ОЗУ может перестать хватать примерно на ~2000 соединений).
    Порты, которые я добавил:

    • 20, 21 FTP

    • 80, 443, 8080–8880 HTTP/HTTPS

    • 110, 143, 465, 587, 993, 995 почта

    • 2000–2099 есть информация, что используются для Discord

  • Destination UDP Port to Proxy перенаправление UDP-портов в sing-box:

    • 443 QUIC

    • 19294–19344, 50000–50032 Discord

  • Bypass DSCP пропуск трафика с определённой DSCP-меткой.

Настройки портов, куда перенаправляется трафик, в Momo нет, он читает их из конфигурации sing-box.

Составление конфигурации sing-box

Sing-box использует JSON-формат конфига, описанный на официальном сайте. Здесь упомяну только то, что нам потребуется.

Каркас конфигурации

{
  "log": {},
  "dns": {},
  "endpoints": [],
  "inbounds": [],
  "outbounds": [],
  "route": {},
  "experimental": {}
}

Раздел log

Задаёт уровень логов, файл для вывода и т.д.
https://sing-box.sagernet.org/configuration/log/

"log": {
  "level": "warn"
},

Раздел dns

Позволяет задать DNS-серверы, на которых будет происходить обработка запросов, и выбирать DNS-сервер в зависимости от домена.
https://sing-box.sagernet.org/configuration/dns/

"dns": {
  "servers": [
    {
      "type": "udp",
      "tag": "yandex-dns",
      "server": "77.88.8.8",
      "detour": "direct-out"
    },
    {
      "type": "udp",
      "tag": "NSDI-dns",
      "server": "195.208.5.1",
      "detour": "direct-out"
    },
    {
      "type": "https",
      "tag": "cloudflare-dns",
      "server": "1.1.1.1",
      "detour": "direct-out"
    },
    {
      "type": "https",
      "tag": "google-dns",
      "server": "8.8.8.8",
      "detour": "direct-out"
    },
    {
      "type": "https",
      "tag": "Quad9-dns",
      "server": "dns.quad9.net",
      "domain_resolver": "yandex-dns",
      "detour": "direct-out"
    }
  ],
  "rules": [
    {
      "rule_set": "geosite-category-ru",
      "server": "NSDI-dns"
    },
    {
      "rule_set": "refilter_domains",
      "server": "Quad9-dns"
    }
  ]
},

Quad9 используется, поскольку этот сервис не передаёт IP клиента, запросившего адрес (были случаи, когда зарубежные DNS намеренно отдавали некорректный адрес при запросе с русского IP).

Раздел endpoints

Позволяет задавать WireGuard и Tailscale-соединения.
https://sing-box.sagernet.org/configuration/endpoint/

"endpoints": [
  {
    "type": "wireguard",
    "tag": "warp",
    "detour": "direct-out",
    "system": false,
    "mtu": 1280,
    "address": [
      "172.16.0.2/32",
      "*:*:*/128"
    ],
    "private_key": "*",
    "peers": [
      {
        "address": "162.159.192.1",
        "port": 2408,
        "public_key": "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=",
        "allowed_ips": [
          "0.0.0.0/0",
          "::/0"
        ],
        "persistent_keepalive_interval": 30,
        "reserved": "dHbH"
      }
    ],
    "amnezia": {
      "jc": 120,
      "jmin": 23,
      "jmax": 911
    }
  }
],

Внимание: amnezia доступна только при использовании форка.

Раздел inbounds

Здесь настраиваются способы получения трафика.
https://sing-box.sagernet.org/configuration/inbound/

"inbounds": [
  {
    "type": "tproxy",
    "tag": "tproxy-in",
    "listen": "::",
    "listen_port": 12345,
    "tcp_fast_open": true
  },
  {
    "type": "direct",
    "tag": "dns-in",
    "listen": "::",
    "listen_port": 5354
  }
],

Важно: блоки tproxy-in и dns-in надо называть именно так, Momo ищет их при чтении файла, чтобы получить порт. Можно дополнительно создать mixed-прокси, для которого весь трафик будет идти в туннель.

Раздел outbounds

Выходы для трафика: нужно настроить прокси, через который будет выводиться заблокированный трафик. При использовании форка доступны дополнительные типы, включая XHTTP.
https://sing-box.sagernet.org/configuration/outbound/

"outbounds": [
  {
    "type": "direct",
    "tag": "direct-out",
    "connect_timeout": "20s",
    "domain_resolver": {
      "server": "yandex-dns",
      "strategy": "ipv4_only"
    }
  },
  {
    "type": "urltest",
    "tag": "block-check",
    "outbounds": [
      "warp",
      "tunnel"
    ],
    "url": "http://cp.cloudflare.com/generate_204",
    "interval": "1m"
  },
  {
    "packet_encoding": "xudp",
    "server": "*",
    "server_port": 443,
    "uuid": "*",
    "type": "vless",
    "tag": "tunnel",
    "tcp_fast_open": true,
    "tcp_multi_path": true,
    "reuse_addr": true,
    "flow": "xtls-rprx-vision",
    "tls": {
      "enabled": true,
      "server_name": "*",
      "utls": {
        "enabled": true,
        "fingerprint": "firefox"
      },
      "reality": {
        "enabled": true,
        "public_key": "*",
        "short_id": "*"
      }
    },
    "domain_resolver": {
      "server": "Quad9-dns",
      "strategy": "prefer_ipv6"
    }
  }
],
  • direct отправляет трафик напрямую.

  • urltest позволяет выбрать наиболее быстрый/рабочий outbound (поддерживает endpoints).

  • Для каждого outbound можно задать, какой DNS-сервер использовать и как выбирать IP (стратегии: ipv4_only, prefer_ipv6 и т.д.).

Раздел route

Один из ключевых разделов: определяет, какой трафик куда пойдёт. Также позволяет подключать rule_set, подготовленные другими людьми.
https://sing-box.sagernet.org/configuration/route/

Я вижу два основных подхода:

  1. Направить все соединения к российским ресурсам напрямую; остальное в туннель.

  2. Направлять в туннель только то, что есть в списках заблокированного; всё остальное напрямую.

Также можно сочинить множество собственных правил (например, для блокировки рекламы). Я знаю два возможных источника списков заблокированного:

  • antizapret-sing-box: огромный список; с большой вероятностью там будет любой заблокированный ресурс, но из-за отсутствия аккуратной очистки там много мёртвых доменов, что негативно влияет на производительность и потребление памяти.

  • Re-filter-lists: попытка создать более чистый список (была статья на Хабре). Минусы: автор редко обновляет список (раз в пару месяцев или реже) и принимает решения о добавлении доменов по своим критериям. (Личный пример: я предложил три аниме-сайта с подтверждением блокировки с сайта Роскомнадзора, включая известный MyAnimeList; все три предложения были отклонены без объяснения. Другие предложения, в том числе мои, обрабатывались нормально.)

В примерах ниже использую Re-filter.

Вариант направления по спискам

"route": {
  "rules": [
    {
      "action": "sniff"
    },
    {
      "protocol": "dns",
      "action": "hijack-dns"
    },
    {
      "inbound": "dns-in",
      "action": "hijack-dns"
    },
    {
      "ip_is_private": true,
      "outbound": "direct-out"
    },
    {
      "protocol": "bittorrent",
      "outbound": "direct-out"
    },
    {
      "rule_set": "refilter_domains",
      "outbound": "block-check"
    },
    {
      "action": "resolve",
      "strategy": "ipv4_only"
    },
    {
      "rule_set": "refilter_ipsum",
      "outbound": "block-check"
    }
  ],
  "rule_set": [
    {
      "tag": "refilter_domains",
      "type": "remote",
      "format": "binary",
      "url": "https://github.com/1andrevich/Re-filter-lists/releases/latest/download/ruleset-domain-refilter_domains.srs"
    },
    {
      "tag": "refilter_ipsum",
      "type": "remote",
      "format": "binary",
      "url": "https://github.com/1andrevich/Re-filter-lists/releases/latest/download/ruleset-ip-refilter_ipsum.srs"
    }
  ],
  "auto_detect_interface": true,
  "default_domain_resolver": "google-dns"
},

Объяснение правил:

  • sniff позволяет sing-box определить протокол трафика. Без него нельзя узнать, что трафик DNS, bittorrent и т.д.

  • hijack-dns перенаправляет обработку DNS во внутренний DNS sing-box. Отдельно для dns-in потому что у меня был случай, когда трафик не распознавался как DNS, и тысячи UDP-соединений забили память роутера.

  • ip_is_private если на tproxy попали соединения на локальные IP, их нужно отправить напрямую (Momo, по идее, не должен их заворачивать, но перестраховка не лишняя).

  • bittorrent если торрент-трафик оказался на портах, которые мы заворачиваем на sing-box, лучше направить его напрямую (включая соображения возможных проблем от хостера).

  • refilter_domains и refilter_ipsum разделены, т.к. туннель может иметь IPv6-адрес при отсутствии такового у провайдера; при попадании на соответствующий outbound разрешение будет происходить по правилам этого outbound.

  • resolve меняем в зависимости от наличия или отсутствия IPv6 у домашнего провайдера.

Вариант: российские ресурсы напрямую, остальное в туннель

"route": {
  "rules": [
    {
      "action": "sniff"
    },
    {
      "protocol": "dns",
      "action": "hijack-dns"
    },
    {
      "inbound": "dns-in",
      "action": "hijack-dns"
    },
    {
      "ip_is_private": true,
      "outbound": "direct-out"
    },
    {
      "protocol": "bittorrent",
      "outbound": "direct-out"
    },
    {
      "rule_set": "geosite-category-ru",
      "outbound": "direct-out"
    },
    {
      "action": "resolve",
      "strategy": "ipv4_only"
    },
    {
      "rule_set": "geoip-ru",
      "outbound": "direct-out"
    }
  ],
  "rule_set": [
    {
      "tag": "geosite-category-ru",
      "type": "remote",
      "format": "binary",
      "url": "https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geosite-category-ru.srs"
    },
    {
      "tag": "geoip-ru",
      "type": "remote",
      "format": "binary",
      "url": "https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geoip-ru.srs"
    }
  ],
  "auto_detect_interface": true,
  "default_domain_resolver": "google-dns",
  "final": "block-check"
},

final sing-box по умолчанию отправляет трафик в первый outbound; с помощью final можно переопределить выход по умолчанию.

Раздел experimental

Позволяет управлять хранением кэша rule_set и включить внешний мониторинг.
https://sing-box.sagernet.org/configuration/experimental/

"experimental": {
  "cache_file": {
    "enabled": false
  },
  "clash_api": {
    "external_controller": "[::]:9090"
  }
}

Здесь я отключаю кэш, чтобы приложение лишний раз не записывало в постоянную память роутера. Мониторинг можно посмотреть через YACD
Внимание: если открыть HTTPS-версию вместо HTTP, современные браузеры могут разрешать доступ только к localhost, это ограничение браузеров ради безопасности (чтобы сайты не могли сканировать локальную сеть).

Пример окна мониторинга:

Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 12
Настройка sing-box и Momo (TPROXY) на OpenWrt: быстрый и точный обход блокировок - 13

Дополнительно

  • Для перенаправления на TPROXY требуются пакеты kmod-nf-tproxy и kmod-nft-socket.

  • Если у вас, как и у меня, не работает китайский репозиторий (у меня он заблокирован и даже через европейский прокси не работает), просто скачайте из релизов пакеты под вашу архитектуру и установите, например: momo_2025.08.11-r3_aarch64_cortex-a53.ipk и luci-app-momo_1.0.5-r1_all.ipk.

  • Рекомендую установить kmod-tcp-bbr, он даёт преимущества BBR для всех tcp соединений, которые будут идти через sing-box.

  • Чтобы уменьшить шанс падения при нехватке памяти при неожиданно большом количестве соединений, можно поставить zram-swap.

  • После установки sing-box отключите его сервис, дальше его будет запускать Momo. Внимание: OpenWrt отключает автозагрузку только после перезапуска.

  • Можно попробовать избежать падений, добавив в init.d-файл Momo значение переменной окружения GOMEMLIMIT с нужным лимитом. Это заставит sing-box раньше вызывать сборщик мусора, но замедлит его в эти моменты. Для 256 МБ памяти без использования zram-swap разумный лимит около 100 МБ.

Методы установки DSCP метки

  • transmission поддерживает установку меток через параметр peer_socket_tos. Исходный код

  • qBittorrent имеет параметры peer-tos и peer-dscp но по информации от 23 года добавляет метку не изначально а уже после установления соединения с пиром что мешает обработке соединений правилами.

  • в Windows можно любому приложению задать DSCP групповой политикой или через powershell команды.

New-NetQosPolicy -Name "qb" -AppPathNameMatchCondition "qbittorrent.exe" -PolicyStore GPO:localhost -DSCPAction 8
Get-NetQosPolicy
Remove-NetQosPolicy -Name "qb"

Автор: abubaca4

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js